SSR 与 Hydration

1. 核心流程

  1. 服务端 (Server):
    • 创建 Vue 实例。
    • 执行组件代码(同步数据预取)。
    • renderToString 生成 HTML 字符串。
    • 注入 window.__INITIAL_STATE__
  2. 客户端 (Client):
    • 下载 JS 包。
    • createSSRApp 创建实例。
    • Hydration (激活/水合):Vue 实际上不会重新渲染 DOM,而是尝试去匹配现有的服务器 HTML,只做事件绑定和响应式初始化。

2. 水合不匹配 (Hydration Mismatch)

这是 SSR 最常见的问题。 现象:控制台报错 Hydration node mismatch,Vue 被迫丢弃服务端 HTML,在客户端重新渲染(导致性能损耗和闪烁)。

常见原因

  1. 无效的 HTML 嵌套:比如 <p> 里面包了 <div>(浏览器会自动修正 HTML 结构,导致 Vue 找不到对应的节点)。
  2. 不确定性数据
    • Date.now() / Math.random():服务端执行结果和客户端不一致。
    • typeof window 判断:服务端渲染了 A,客户端判断有 window 渲染了 B。

解决

  • 确保 v-if/else 逻辑在双端一致。
  • 对于必须依赖浏览器的组件(如 <ClientOnly>),使用 <ClientOnly> 包裹或 onMounted 后再渲染。

3. 注意事项

  • 生命周期:服务端只执行 beforeCreatecreatedmounted 不会执行。
  • 单例污染:在服务端,每个请求必须创建一个新的 App 实例Store 实例,否则多用户会公用同一个状态。