Vue 프로젝트 도중 겪은 Github Issue로 해결까지

데브현·2023년 9월 15일
1

프론트엔드 모음집

목록 보기
4/17

vue로 구성된 프로젝트를 진행하던 도중에 router.push 로 라우터 이동 도중에 계속 에러가 났었다.

그 에러는 inserBefore 에러...
원인을 찾고 싶었는데 sourcemap 도 vue core 자체에서 나고 디버깅이 어려워 결국 시도해본 방법은 코드를 최소한으로 구성해 테스트해보는 것이였다.

문제의 코드 구조

코드는 간단하게만 작성하겠다.

// App.vue
<template>
  <RouterView />
</template>

// PageA.vue
<template>
<Container>
  <template v-slot:body>
    <div class="about">
      <h1>This is an PageA</h1>
      <Content></Content>
    </div>
  </template>
  <teleport to="#app">
    <div class="teleport">move</div>
  </teleport>
</Container>
</template>

// PageB.vue
<template>
<Container>
  <template v-slot:body>
    <div class="home">
      <h1>This is an PageB</h1>
      <button @click="onClick">PageA 이동</button>
    </div>
  </template>
</Container>
</template>

// Content.vue
<template>
<Container2>
  <template v-slot:body>
    ...
    <teleport to="#app">
      <div class="teleport">move</div>
    </teleport>
  </template>
</Container2>
</template>

전체적인 코드의 구조는 위처럼인데, 일단 Router view가 PageA/PageB 두개로 나뉘어져 있고,
해당 페이지들은 Container라는 컴포넌트로 감싸여 있다.
그리고 하나의 컴포넌트(여기선 PageA)에는 Content와, Modal 이 존재했다.
그런데 Content 컴포넌트 또한 모달이 있고, 다른 컨테이너로 씌워진 컴포넌트였다.

전반적인 컴포넌트는 이렇게 구성되어있고 내가 이제 버그를 찾아보자

시도한 방법

먼저 구조가 Container로 감싸여 있는게 여러개고 Teleport하는 코드도 여러개다 보니 하나씩 테스트 해보았다.

방법 1 - slot이 문제일까?

해당 오류가 떠서 나는 v-slot을 중첩으로 사용하는게 문제인가 했다.
그래서 v-slot을 중첩으로 사용했을때 router.push를 하면 문제가 생기는게 아닐까?
해서 Content.vue 의 Container를 제거하고 테스트해보았다.

// Content.vue
<template>
  <div>
    ...
    <teleport to="#app">
      <div class="teleport">move</div>
    </teleport>
  </div>
</template>

그러나 역시나 실패 🥲

방법 2 - 외부에 선언한 teleport가 문제일까?

// PageA.vue
<template>
<Container>
  <template v-slot:body>
    <div class="about">
      <h1>This is an PageA</h1>
      <Content></Content>
    </div>
  </template>
  <!-- <teleport to="#app">
    <div class="teleport">move</div>
  </teleport> -->
</Container>
</template>

PageA 컴포넌트같은 경우에 외부에 teleport하는 모달이 있는데 이것 때문에 버그가 생기나해서 지워봤지만
역시나 해결되지 않았다.

방법 3 - 그럼 Content의 teleport가 문제?

// Content.vue
<template>
<Container2>
  <template v-slot:body>
    ...
    <!-- <teleport to="#app">
      <div class="teleport">move</div>
    </teleport> -->
  </template>
</Container2>
</template>

해당 teleport 구문을 제거하니 문제가 사라졌다.
그래서 이제 원인을 찾았으니 고쳐야 하는데... 아무리봐도 저게 왜 문제인지 이해가 안갔다.
외부의 teleport to="#app" 은 문제없이 작동하는데 왜 내부의 컴포넌트에서는 안되는것인가.. 라는 고민에 빠져 이것 저것 해보다가 '#app' 으로 텔레포트 시키는게 문제라고 판단되어 최상위 컴포넌트의 클래스로 teleport를 시켰다.

그랬더니 문제 없이 동작한다...!

버그를 예상해보면 #app은 vue의 createApp의 entry포인트이고, 그렇게되면서 라우터 이동과 텔레포트가 동시에 동작을 해서 오류를 내뿜는? 것 같아서 바로 github issue에 등록했다.

이슈의 내용을 간단히 요약하고, 코드를 제출해 보고했더니 얼마지나지 않아 Vue측에서도 minor-bug 로 판단하여 PR을 들어가 수정하고 Issue를 closed 했다.

Before executing 'unmount,' the 'anchor' was obtained. After 'unmount' completes, it is possible that the 'anchor' has been removed, causing an error when trying to find the 'anchor' during a subsequent 'mount.' This scenario only occurs when the 'anchor' is the last node. Therefore, using 'parent.appendChild(child)' for mounting is recommended.

'unmount'를 실행하기 전에 'anchor'를 획득했습니다. 'unmount'가 완료된 후 'anchor'가 제거되어 후속 'mount' 중에 'anchor'를 찾으려고 할 때 오류가 발생할 수 있습니다. 이 시나리오는 'anchor'가 마지막 노드인 경우에만 발생합니다. 따라서 'parent.appendChild(child)'를 사용하여 마운트하는 것을 권장합니다.

PR 내용을 살펴보니 이런 댓글이 남겨져 있엇는데, 해석해보자면 router.push로 이동할때 unmount가 일어나고, 그 과정에서 anchor(여기선 #app이고, 마지막 노드일 경우에만 해당)이 제거되어 오류가 발생했으니 부모에 appendChild해서 마운트하도록 고쳐라 라는 내용인 것 같다.

아마 3.3.4 다음 버전에 Fix될 것으로 보인다.

github issue에 제보해서 등록한게 bug로 판단되어 고쳐지는것까지의 과정을 겪어보니 신기하면서도 뿌듯... 🤭

profile
I am a front-end developer with 4 years of experience who believes that there is nothing I cannot do.

0개의 댓글