Subscribe on changes!

SSR and Client-Hydrated Vue Components do not fully hydrate to client-rendered DOM as stated in the documentation

avatar
Mar 2nd 2024

Vue version

3.4.21

Link to minimal reproduction

https://stackblitz.com/edit/withastro-astro-7u8olz?file=src%2Fpages%2Findex.astro

Steps to reproduce

Make the preview window viewport < 900px width and reload this preview window (top left). The client:load component will mount but does not re-render with a new "mobile" class like the client:only component does. The orange background denotes the mobile class is applied.

What is expected?

I would expect that, as stated in the docs (last paragraph of: https://vuejs.org/guide/scaling-up/ssr.html#hydration-mismatch), when Vue SSR hydration encounters a hydration mismatch it recovers by replacing the server-rendered DOM with the client-rendered DOM.

What is actually happening?

Dynamic attributes and classes on the hydrated component do not update upon hydration and mounting. Other values, like rendered ref values within the template do update.

System Info

(Local System)

System:
    OS: macOS 14.3.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 417.05 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.5.1 - ~/.nvm/versions/node/v20.5.1/bin/node
    Yarn: 1.22.5 - ~/.yarn/bin/yarn
    npm: 9.8.0 - ~/.nvm/versions/node/v20.5.1/bin/npm
  Browsers:
    Chrome: 122.0.6261.94
    Chrome Canary: 124.0.6333.0
    Edge: 122.0.2365.63
    Safari: 17.3.1
    Safari Technology Preview: 17.4

AND

(Stackblitz)

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.18.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.3 - /usr/local/bin/pnpm
  npmPackages:
    vue: ^3.4.21 => 3.4.21

Any additional comments?

I understand that other than the docs being confusing, this may not be considered a bug. Hydration mismatch is looked at as an error to be fixed at development time. But I think that idea is wrong in the circumstance that progressive enhancement is an incredibly useful feature to allow a component to partially render, and then fully hydrate to an enhanced state.

I also have a separate reproduction using Nuxt showing the exact same behavior to rule out that Astro is interfering in the first reproduction: https://stackblitz.com/edit/nuxt-starter-patbx4