Sometimes, we need to redirect to another location before the page finishes rendering. For example, in the following snippet,
VuePress will try to redirect unknown request /foo to /foo.html and /foo/. Other scenarios include redirecting / to /zh/ or /en/ based on navigator language.
The snippet referenced above will work fine for most of the conditions. But if the page needs redirecting before rendering starts, uses server-side rendering and the pages before and after redirecting do not share an identical structure, this will lead to the problem called SSR Mismatch.
An example of handleRedirectForCleanUrls to explain the mismatch
You request`/foo` in the browser, but the server can't find a direct match (without certain config), so a NotFound page `/404.html` will be returned. The `beforeEach` hook registered in `handleRedirectForCleanUrls` will redirect the router to `/foo.html`. Note that the DOM remains unchanged but the VDOM is replaced with `/foo.html`'s. Normally, `/404.html` is a plain page without navbar and sidebar, but the new VDOM is a document page with such components. The DOM fails to match the VDOM, causing rendering error and the view will not be updated. This is an SSR Mismatch and its consequence.
Summarize the bug-like problem as follow.
The server-side rendered pages need a hydration stage to be fully functional and the hydration stage needs corresponding DOM and VDOM structure (a correctly server-side rendered website could easily achieve this).
But, when at least one of DOM and VDOM changes before hydration, DOM and VDOM mismatch will happen, especially in production distribution of Vue where the mismatch warning is indirect and the re-rendering fallback is removed (see this issue in the Vue repository).
Redirecting may be the most reasonable way for such condition to happen as the VDOM is changed and the pages before and after redirecting do not have identical VDOM structure.
The feature request aims to solve this problem.
What I propose here is that VuePress should handle the problem internally for end users and plugin developers, for example, by postponing the redirection.
If it can't be solved gracefully, at least, the document should explicitly point this caveat out.
I mentioned bug-like above because I know it is not a bug of Vue Server Renderer or Vue Router. Instead, it should be addressed by the app itself. But developers may easily ignore this and waste much time debugging because the bug only exists in build mode with server-side rendering enabled. Even VuePress' official code (the snippet referenced above) has such problem as well.
I'm willing to participate in. Actually, I have experimented for a while but can't solve the problem without glitch. So, I post it out and seek help.
Also, Vue component, such as <TOC/>, can also lead to SSR mismatch if the corresponding page is opened without being redirected. Also, any <router-link> in an SSR-mismatched page will fail, which I think is indeed a serious problem.
I made a mistake. This problem exists in every markdown-it plugin (markdown-it-table-of-contents, markdown-it-toc, markdown-it-toc-and anchor...... you name it). Even in the 0.x documentation we can see an extra <p>. It's just using a component that expose the SSR mismatching problem.
Normal SSR
urlA -> server -> redirect urlB -> render pageB -> client get pageB -> vue hydrate pageB with pageB (OK)
Current VuePress "SSR"
urlA -> server -> "render" pageA -> client get pageA -> redirect urlB -> vue hydrate pageB with pageA (fuck!)
I have created a plugin vuepress-plugin-dehydration to temporarily workaround this issue.
I have created a repro for users to test this issue, Thanks to @Shigma's great work!
Most helpful comment
I have created a repro for users to test this issue, Thanks to @Shigma's great work!