脱水时 HTML 必须带 data-server-rendered="true" 属性,这是客户端 Vue/React 判断 DOM 是否由服务端生成的唯一依据;漏掉会导致 hydration 失败,退化为纯 CSR 渲染,引发页面闪烁、状态重置、事件不绑定等问题。

脱水时 HTML 必须带 data-server-rendered="true" 属性
服务端渲染出的每个根组件容器(比如 <div id="app">)必须显式添加 data-server-rendered="true",这是客户端 Vue/React 判断“该 DOM 是否由服务端生成”的唯一依据。漏掉这个属性,框架会直接跳过 hydration,退化为纯 CSR 渲染——页面闪一下、状态重置、事件不绑定,全部发生。
常见错误现象:首屏内容正常,但点击无响应、表单输入丢失、v-model 不同步。检查 DOM 就会发现所有节点都没有该属性,或只在部分组件上写了(比如只加在顶层 div,但子组件没继承)。
- Vue SSR 中,
vue-server-renderer默认自动注入,但若手动拼接 HTML 或使用自定义模板,必须自己补上 - React 中需确保
ReactDOMServer.renderToString()输出的根节点含该标记,或在模板中硬编码 - Next.js/Nuxt 等框架已封装,但自研 SSR 时极易忽略
注水前必须校验 __INITIAL_STATE__ 并还原 store/data
客户端 JS 执行 hydration 前,第一步不是挂载组件,而是读取内联的 <script id="__INITIAL_STATE__" type="application/json"> 并还原初始状态。如果这一步失败或还原错位,后续所有 VNode diff 都会失准,触发 hydration mismatch。
典型问题场景:
立即学习“前端免费学习笔记(深入)”;
- 服务端序列化了 Date 对象或 Map/Set,客户端 JSON.parse 后变成 plain object,导致响应式失效
- store 初始化逻辑里用了
window或document,服务端执行报错,快照为空 - 客户端用不同 key 名读取(比如服务端写
state,客户端读__INITIAL_DATA__)
建议做法:统一用 JSON.parse(document.getElementById('__INITIAL_STATE__')?.textContent || '{}'),并在还原后做类型校验(如检查 user.id 是否为 number)。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
服务端与客户端 render 函数输出必须结构一致
hydration 的核心比对逻辑,是拿客户端首次调用 render() 生成的 VNode 树,逐节点对比服务端 HTML 的 DOM 结构。只要有一处不一致(哪怕只是属性顺序、空格、注释、条件分支走错),就会抛 Hydration mismatch 警告并强制丢弃服务端 HTML。
最容易踩的坑:
- 服务端用
process.env.NODE_ENV === 'production',客户端用import.meta.env.PROD,导致环境判断结果不一致 - 组件里用了
Math.random()或new Date().getTime()生成 key 或文本,服务端和客户端值必然不同 - 服务端没执行
serverPrefetch或getServerSideProps,数据为空,客户端却有默认值,导致条件渲染分支不同 - SSR 时 CSS-in-JS(如 styled-components)未正确 extract,服务端样式缺失,影响元素是否渲染
静态资源路径和 base href 必须两端一致
HTML 中的 <link rel="stylesheet">、<script src>、图片 src 等路径,若服务端渲染时用的是相对路径(如 /static/css/app.css),而客户端运行时实际部署在子路径(如 https://example.com/my-app/),就会加载失败——进而导致样式缺失、JS 报错、hydration 中断。
解决方案很实在:
- 服务端模板中用统一变量注入 base URL,比如
<base href=""> - Webpack 构建时设
output.publicPath与运行时一致 - Vite 用户注意:
base配置必须在 SSR 和 CSR 两端生效,不能只配vite.config.ts里的 client 部分
这个点常被当成“部署问题”忽略,但它直接影响 hydration 能否完成——连事件监听器都绑不上,还谈什么同构。


















