Subscribe on changes!

Should silently fail hydrating empty container in production

avatar
Jul 1st 2021

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
    }
avatar
Jul 1st 2021

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

avatar
Jul 1st 2021

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.

avatar
Apr 23rd 2023

Thanks Trinovantes , helps me a lot