본문으로 건너뛰기

[Open WebUI] Tooltip 컴포넌트의 tippy 인스턴스 메모리 누수 수정 및 타입 정의 개선

PR 링크: open-webui/open-webui#21969 상태: Merged | 변경: +32 / -20

들어가며

Open WebUI의 Tooltip.svelte 컴포넌트는 tippy.js를 사용하여 툴팁을 렌더링합니다. 기존 구현에서 tooltipElement가 변경되면 reactive 블록이 새로운 tippy 인스턴스를 생성하지만, 이전 인스턴스의 참조 요소가 달라졌는지 확인하지 않아 분리된 tippy 플로팅 DOM이 메모리에 잔존했습니다.

핵심 코드 분석

Before: 요소 변경 시 이전 인스턴스 미정리

<script>
  let tooltipElement;
  let tooltipInstance;

  $: if (tooltipElement && (content || elementId)) {
    if (tooltipInstance) {
      tooltipInstance.setContent(tooltipContent);  // 요소가 바뀌어도 setContent만 호출
    } else {
      tooltipInstance = tippy(tooltipElement, { ... });
    }
  } else if (tooltipInstance && content === '') {
    if (tooltipInstance) {
      tooltipInstance.destroy();
    }
  }
</script>

After: 요소 변경 감지 후 destroy + 재생성

<script>
  let tooltipElement: HTMLElement | null = null;
  let tooltipInstance: TippyInstance | null = null;

  function destroyInstance() {
    if (tooltipInstance) {
      tooltipInstance.destroy();
      tooltipInstance = null;
    }
  }

  $: if (tooltipElement && (content || elementId)) {
    // 요소가 바뀌면 이전 인스턴스 정리
    if (tooltipInstance && tooltipInstance.reference !== tooltipElement) {
      destroyInstance();
    }

    if (tooltipInstance) {
      tooltipInstance.setContent(tooltipContent ?? '');
    } else {
      if (content) {
        tooltipInstance = tippy(tooltipElement, { ... });
      }
    }
  } else if (tooltipInstance && content === '') {
    destroyInstance();
  }

  onDestroy(() => { destroyInstance(); });
</script>

왜 이게 좋은가

  1. 참조 비교로 누수 방지: tooltipInstance.reference !== tooltipElement 비교를 통해 요소가 바뀌면 이전 인스턴스를 즉시 파괴한다.
  2. destroyInstance 함수 추출: destroy + null 할당을 한 곳에서 관리하여 실수를 방지한다.
  3. TypeScript 타입 적용: TippyPlacement, TippyProps, TippyInstance 등 정확한 타입을 사용하여 런타임 오류 가능성을 줄였다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글