Skip to content

Page redirection fails due to SSR mismatch #1382

@jjyyxx

Description

@jjyyxx

Feature request

What problem does this feature solve?

Sometimes, we need to redirect to another location before the page finishes rendering. For example, in the following snippet,

export function handleRedirectForCleanUrls (router) {
router.beforeEach((to, from, next) => {
if (isRouteExists(router, to.path)) {
next()
} else {
if (!/(\/|\.html)$/.test(to.path)) {
const endingSlashUrl = to.path + '/'
const endingHtmlUrl = to.path + '.html'
if (isRouteExists(router, endingHtmlUrl)) {
next(endingHtmlUrl)
} else if (isRouteExists(router, endingSlashUrl)) {
next(endingSlashUrl)
} else {
next()
}
} else if (/\/$/.test(to.path)) {
const endingHtmlUrl = to.path.replace(/\/$/, '') + '.html'
if (isRouteExists(router, endingHtmlUrl)) {
next(endingHtmlUrl)
} else {
next()
}
} else {
next()
}
}
})
}

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.

  1. 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).

  2. 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).

  3. 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 does the proposed API look like?

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.

How should this be implemented in your opinion?

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.

Are you willing to work on this yourself?

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions