Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teleport SSR mismatches and breaks the app #5242

Closed
emarbo opened this issue Jan 11, 2022 · 7 comments
Closed

Teleport SSR mismatches and breaks the app #5242

emarbo opened this issue Jan 11, 2022 · 7 comments

Comments

@emarbo
Copy link

emarbo commented Jan 11, 2022

Version

3.2.26

Reproduction link

This is the simplest project created using vue-cli-service with 4 pages with one happy path and three teleport scenarios:

Teleport demo

Steps to reproduce

Setup the project:

npm install
npm run build

Start the server (SSR):

npm run serve-prod

Access to the home and browse all pages, to see the expected behaviour (everything works fine).

Then access to the one teleport, two teleports and nested teleport cases (direct access or page refresh to trigger the SSR) to experiment several kinds of errors (see additional comments below).

What is expected?

Client and server HTML should match, and so there shouldn't be SSR mismatches. Even when there are no mismatches, the app should not break after changing the view (one teleport case).

What is actually happening?

The hydration fails for the two and nested teleports cases. In all cases where a teleport is SSRed, the app fails (disappears from the DOM) when trying to change the view.


All cases tested:

Happy path

Access to the home at http://localhost:8010/ and browse through the different pages:

  • Home
  • One teleport
  • Two teleport
  • Nested teleport

Everything works as expected. Teleports appear and disappear on all views as they should do.

One teleport case

Access to http://localhost:8010/one-teleport directly to trigger the SSR. What happens:

  • No hydration errors
  • After browsing to another page, the app disappears from the DOM.

Two teleport case

Access to http://localhost:8010/two-teleport directly to trigger the SSR. What happens:

  • Hydration errors on the console
  • After re-rendering (due to hydration errors), the second teleport appears twice in the DOM.
  • After browsing to another page, the app disappears from the DOM.

Nested teleport case

Access to http://localhost:8010/nested-teleport directly to trigger the SSR. What happens:

  • Hydration errors on the console
  • After re-rendering (due to hydration errors), the app disappears from the DOM
@Xing-He
Copy link

Xing-He commented Feb 25, 2022

  • SSR + Vite + Vue3 + Element-Plus
    Same error with teleport, but i got an "null" access error as below.
    and then, all router operations will be a failure

  • runtime-core.esm-bundler.js#L4807

if (shapeFlag & 64 /* TELEPORT */) {
        vnode.type.remove(vnode, parentComponent, parentSuspense, optimized, internals, doRemove);
}

runtime-dom.esm-bundler.js#L13

remove: child => {
       // ERROR ->  child is null
        const parent = child.parentNode;
        if (parent) {
            parent.removeChild(child);
        }
}

@Xing-He
Copy link

Xing-He commented Feb 26, 2022

After searching Element-plus's issues, I found that it may be an element issue. Now, I have to ignore rendering components using teleport at SSR, instead of rendering by CSR after mounted.

@yyx990803
Copy link
Member

yyx990803 commented May 18, 2022

General note: avoid targeting body with Teleport during SSR, because this makes it impossible for the Teleport to locate the correct starting location for hydration with other potential content. Instead, use a dedicated element:

<body>
  <div id="app">...</div>
  <div id="teleports"><!-- target teleports here --></div>
</body>

With this structure, both single and double teleports work as intended.

Nested teleports are supported after 595263c.

@mythshuazi
Copy link

mythshuazi commented Jun 6, 2022

@Xing-He I use Element-plus get the same warn tips. How did you solve the problem?Can you provide your code reference? Thanks a lot~

@Xing-He
Copy link

Xing-He commented Jun 8, 2022

@mythshuazi Element使用的组件有些存在是否选用teleport的参数,这个可以试试,我的处理比较粗暴些,因为一般使用了teleport的组件都是些input select啥的,SEO的时候其实也不需要获取这些节点数据,因此就采用了页面加载完成后再渲染出来,直接v-if="mounted"

@mythshuazi
Copy link

@mythshuazi Element使用的组件有些存在是否选用teleport的参数,这个可以试试,我的处理比较粗暴些,因为一般使用了teleport的组件都是些input select啥的,SEO的时候其实也不需要获取这些节点数据,因此就采用了页面加载完成后再渲染出来,直接v-if="mounted"

@Xing-He 我的处理方法和你差不多,但是这个repo vue3-ts-vite-ssr-starter搭的ssr 没有 mismatch的问题,我一直没看找到原因,一起看看?

@emarbo
Copy link
Author

emarbo commented Jun 21, 2022

Hi there, sorry for the late reply. I have updated the demo project to the latest Vue version and changed from body to #body-teleports and everything worked as expected. Thanks for the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants