core icon indicating copy to clipboard operation
core copied to clipboard

`TypeError` when Teleport target and RouterView share the same ancestor or if Teleport target is a component

Open alinnert opened this issue 2 years ago • 4 comments

Vue version

3.3.4

Link to minimal reproduction

https://codesandbox.io/p/sandbox/immutable-wildflower-lfktcx?file=/src/components/AppLayout.vue:12,37

Steps to reproduce

Click on "Open dashboard" and switch between pages A and B using the "Open page A" and "Open page B" links. Open the debugger so you can see potential warnings and errors.

The file AppLayout.vue contains comments and a few cases that make the app work or not work.

What is expected?

The Teleport target (<div id="toolbar">) should get populated with buttons no matter where it's located in the template. Or the edge cases should get documented.

What is actually happening?

Opening the "dashboard" doesn't populate the "toolbar" and it outputs a warning in the console that the Teleport target is null. When switching between the pages it outputs the error:

Uncaught TypeError: Cannot read properties of null (reading 'type')
    at unmountComponent (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7682:18)
    at unmount (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7593:7)
    at Object.remove (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7989:11)
    at unmount (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7603:20)
    at unmountChildren (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7712:7)
    at unmount (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7613:9)
    at unmountComponent (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7692:7)
    at unmount (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7593:7)
    at unmountComponent (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7692:7)
    at unmount (/node_modules/.vite/deps/chunk-J6475X5X.js?v=02e838b0:7593:7)

I could figure out two cases where Teleports don't work:

  1. If the Teleport target and <router-view> share the same ancestor in a template - unless the Teleport target is at the template root level, then it does work. In that case moving either the Teleport target or the <router-view> out of the common ancestor does solve the issue.
  2. If the Teleport target is a component instead of an HTML element.

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz
    Memory: 2.12 GB / 15.71 GB
  Binaries:
    Node: 20.7.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - C:\var\npm\yarn.CMD
    npm: 9.7.1 - C:\var\npm\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (117.0.2045.31)
    Internet Explorer: 11.0.19041.1566
  npmPackages:
    vue: ^3.3.4 => 3.3.4

Any additional comments?

As I've mentioned in https://github.com/vuejs/core/pull/6908#issuecomment-1729590685 the error is probably caused by this line because vnode.component is null in the error cases which gets ignored:

https://github.com/vuejs/core/blob/fe6f0698bb9de6e39196468baf92c1abc26ca510/packages/runtime-core/src/renderer.ts#L2099

But I can't tell if this is a bug or if Teleports aren't supposed to work in those mentioned scenarios.

Other related issues: #5040 #6040

alinnert avatar Sep 21 '23 16:09 alinnert

Even more minimal reproduction not involving <router-view> with a similar error thrown (which is still occurring inside unmountComponent) when the teleport target does not exist: https://stackblitz.com/edit/vitejs-vite-s1bxpv

  1. Open the console. Observe a pretty normal warning saying "Failed to locate Teleport target". This is expected because the teleport target selector is intentionally misspelled.
  2. Click the button. This changes the teleport and the corresponding target. But instead of the same warning, error like TypeError: can't access property "parentNode", child is null is throw (in my app I get TypeError: Cannot read properties of null (reading 'type'), I couldn't make this error to occur here, but both happen when unmounting the component, using the latest version of vue 3.4.24).

andreww2012 avatar Apr 24 '24 09:04 andreww2012

this problem has now resolved by vue now。anyone know how to fix it in develop project?

chengkai2022 avatar May 28 '24 11:05 chengkai2022

This is not fixed in the latest update (3.4.28).

For me this error only doesn't occur if I place some hardcoded text into a teleport, like so:

<Teleport to="#foo">
  blah
</Teleport>

While this doesn't produce the error, it does produce a warning:

Failed to locate Teleport target with selector "#main-sticky-footer". Note the target element must exist before the component is mounted - i.e. the target cannot be rendered by the component itself, and ideally should be outside of the entire Vue component tree. 

Failed to locate where? Like where did you look for it? I can see it existing perfectly fine in the inspector.

I don't know if it already exists at the exact time it's looking for it. If it doesn't maybe Vue should render it first, ey? This is a chicken&egg problem, really. The target must exist, but in order for the target to exist, Vue must have done its round of rendering the tree, but it also renders the teleport while doing so.

So maybe rendering a teleport target should get priority somehow. Because in our case it has to sit within the application. No way around it.

thany avatar Jun 14 '24 14:06 thany

If your target consistently renders before your source, you can disable the teleport until onMounted and it should work.

unshame avatar Jun 30 '24 12:06 unshame

fixed via https://github.com/vuejs/core/commit/59a3e88903b10ac2278170a44d5a03f24fef23ef It will be out in v3.5

edison1105 avatar Jul 29 '24 01:07 edison1105