Should silently fail hydrating empty container in production
What problem does this feature solve?
In my SSG app, I have several html files generated by renderToString
(e.g. /index.html
, /about/index.html
). For all other routes, I would like to fallback to an empty app.html
rather than my homepage's /index.html
. This prevents my app from temporarily flashing the homepage before routing to the correct components.
# nginx config
server {
listen 80;
location / {
# Exact route match or app.html
try_files $uri $uri/index.html /app.html;
}
}
<!-- fallback app.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<script defer="" src="/public/main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
// main.js
const app = createSSRApp(App)
app.mount('#app')
This works fine in development but breaks in production due to an Cannot read property 'nodeType' of null
error. I think this is due to the early exit guarded by __DEV__ && !container.hasChildNodes()
condition:
https://github.com/vuejs/vue-next/blob/b46a4dccf656280f9905e1bdc47022cb01c062c3/packages/runtime-core/src/hydration.ts#L60-L69
What does the proposed API look like?
Instead, I believe it should always full mount when !container.hasChildNodes()
and guard the console warning with __DEV__
if (!container.hasChildNodes()) {
if (__DEV__) {
warn(
`Attempting to hydrate existing markup but container is empty. `
`Performing full mount instead.`
)
}
patch(null, vnode, container)
return
}
You can find multiple workarounds like having one index.html that isn't ssr rendered to avoid doing the hydration. After all, you are purposely hydrating the page with the wrong content
I'm currently working around this by manually checking IS_SSR || document.querySelector('#id').hasChildNodes() ? createSSRApp(App) : createApp(App)
This is pretty messy and couples the root app creation step with the DOM.
AFAIK, there's no way to disable hydration in the DOM in Vue 3 since createSSRApp
always assume it should hydrate. Back in Vue 2, removing data-server-rendered
attribute from <div id="app">
is enough to disable hydration.
Thanks Trinovantes , helps me a lot