오픈소스에서 발생한 Event Bubbling 문제를 분석하고 PR로 해결한 과정
매일 오전에 GeekNews를 살펴보는데요
ReactFlow 기반 UI를 구성하는 오픈소스 tersa를 소개하는 글을 봤습니다. 글 링크
UI가 깔끔하고 기능도 군더더기 없어서 이것저것 만져보는 도중 겹쳐있는 UI 요소를 더블 클릭할 때 예상하지 못한 동작이 발생하는 문제를 발견했습니다.
viewport Controls 또는 Toolbar를 더블 클릭하면,
해당 UI가 아닌 canvas 영역의 double-click 이벤트가 실행되는 현상이었습니다.
이는 명확히 의도되지 않은 동작이었고, 문제를 해결하기 위해 tersa의 내부 코드를 분석하게 되었습니다.
tersa란
AI 워크플로우를 쉽게 만들기 위해 개발된 캔버스 형태의 오픈소스 도구. 링크: github
문제 상황
다음 UI 요소를 더블 클릭할 때 문제가 발생했습니다:
- viewport Controls
- Toolbar
- Save Loader

문제 현상:
canvas가 아닌 다른 요소를 클릭했음에도, canvax의 canvas의 onDoubleClick handler가 실행되었습니다.
즉, UI 컴포넌트 → canvas로 event가 전파되고 있었습니다.
원인 분석
React에서 이벤트는 기본적으로 bubbling되는데, child component에서 발생한 이벤트는 parent component로 전파됩니다.
tersa 내부 구조를 보면 ReactFlow canvas가 최상위에 존재하고, Controls, Save Loader와 Toolbar는 내부에 위치합니다.
문제는 Controls, Save Loader와 Toolbar에서 발생한 double-click 이벤트가 event.stopPropagation() 없이 그대로 상위로 전달되고 있었습니다.
결과적으로, canvas의 onDoubleClick handler가 실행되고 있었습니다.
코드 분석
기존 코드:
export const ControlsInner = () => (
<FlowControls ...>
<ThemeSwitcher />
</FlowControls>
);
문제:
FlowControls는 onDoubleClick prop을 지원하지 않기 때문에
event를 차단할 수 없었습니다.
해결 방법
FlowControls의 onDoubleClick 이벤트를 옵셔널 props로 받아서 처리할 수 있었지만, onDoubleClick가 전혀 사용되지않는 기능인데 props로 전달하는 방법이 어색해 최소한의 수정을 위해서 FlowControls를 div로 감싸고 onDoubleClick handler를 추가했습니다.
export const ControlsInner = () => (
<div onDoubleClick={(e) => e.stopPropagation()}>
<FlowControls ...>
<ThemeSwitcher />
</FlowControls>
</div>
);
또한 toolbar.tsx에도 동일하게 적용했습니다:
<Panel
onDoubleClick={(e) => e.stopPropagation()}
>

수정 후 canvas위의 컴포넌트에 더블클릭해도 이벤트가 발생되지않는 걸 확인 후 곧바로 PR 준비를 했습니다.
PR 제출

이미 원인과 문제 해결까지 다 했기때문에 PR을 날리는 건 어렵지않았습니다.
repo의 Contributting 섹션이 잘 작성되어있었고 그대로 지침에 따라서 PR을 진행했습니다.
오픈 소스 첫 PR

PR 내용에는 어떤 문제를 발견했고 방법은 이렇게하고 수정한 컴포넌트, 코드와 테스트 방법까지 한눈에 살펴볼 수 있도록 작성했습니다.
Merge 및 Release 반영

사실 기여한 이후 잠시 잊고 있었는데,
“Merged #143 into main”이라는 메일을 받고 나서야
아, 내가 기여했었지! 라는 생각이 들었고, 이 경험을 기록으로 남기고 싶다는 생각이 들었습니다.
repo의 maintainer에 의해 PR이 최종적으로 merge되었고,
해당 변경 사항은 tersa v2.0.0 릴리즈에 포함되었습니다.
마무리
이번 경험을 통해 외부 오픈소스 코드베이스를 분석하고 문제의 원인을 직접 찾아 수정하는 과정이,
실제 회사에서 발생하는 문제를 해결하는 과정과 크게 다르지 않다는 것을 느낄 수 있었습니다.
특히 단순히 사용하는 입장에서 벗어나,
코드의 동작 방식을 이해하고 문제를 해결한 뒤 PR을 통해 공식 코드베이스에 반영되는 전 과정을 경험한 것은 매우 의미 있는 경험이었습니다.
기여한 코드가 공식 릴리즈에 포함되고 contributor로 등록되는 과정을 보며,
오픈소스 기여가 생각보다 멀리 있는 일이 아니라는 점도 알게 되었습니다.
앞으로도 오픈소스를 사용하는 데 그치지 않고,
문제를 발견하면 적극적으로 개선에 기여하는 개발자가 되고자 합니다.

나도 오픈소스 컨트리뷰터~