core
core copied to clipboard
`TypeError` when Teleport target and RouterView share the same ancestor or if Teleport target is a component
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:
- 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. - 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
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
- 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.
- 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 nullis throw (in my app I getTypeError: 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 vue3.4.24).
this problem has now resolved by vue now。anyone know how to fix it in develop project?
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.
If your target consistently renders before your source, you can disable the teleport until onMounted and it should work.
fixed via https://github.com/vuejs/core/commit/59a3e88903b10ac2278170a44d5a03f24fef23ef It will be out in v3.5