




















之前说到过 Hydration Mismatch 原理,今天来说说 为什么从设计上,它就无法完全避免
SSR 做了两件事:
Hydration 的本质是:
在不重建 DOM 的情况下,让 JS 接管已有 HTML (原理详解)
这里有一个隐含前提:
客户端“重新执行一遍渲染逻辑”,并且结果必须和服务端完全一致 (原理详解)
这是问题的根源。
SSR 架构本质是:
同一套组件逻辑
在两个环境执行:
- Node(服务端)
- Browser(客户端)
问题在于:
这两个环境永远不可能完全一致
<span>{new Date().getMilliseconds()}</span>
服务端输出:
<span>123</span>
客户端执行:
<span>167</span>
结果:
不一致 → mismatch (Vite-plugin-ssr)
所以推导出一个结论:只要渲染依赖“运行时”,就必然存在不一致的可能
从几个维度拆开看:
Date.now()
new Date()
结论:
只要用时间,就有 mismatch 风险 (Vite-plugin-ssr)
服务端没有:
window
document
localStorage
客户端有,典型代码:
if (typeof window !== 'undefined') {
// client logic
}
结果:
直接 mismatch
例如:
if (localStorage.getItem('token')) {
return <Home />
} else {
return <Login />
}
服务端:
客户端:
结果:
DOM 完全不同
Math.random()
uuid()
服务端生成一套
客户端再生成一套
结论:
不可能一致
例如:
再次重复一开始提到的前提:SSR 本质是“重复计算”,而重复计算无法保证一致性
为什么一定要一致?
因为 Hydration 的优化前提是:
复用已有 DOM
而不是重新创建
如果不一致:
框架只能:
这会导致:
SSR 想要:
提前生成 HTML(提高首屏)
但 Hydration 需要:
再执行一遍渲染逻辑
这本身就是:
一次“重复执行系统”
而所有重复执行系统都有一个问题:
一致性无法保证
常见手段:
// server 计算
const data = fetch()
// 注入 HTML
window.__INITIAL_DATA__ = data
useEffect(() => {
// client only
}, [])
不要在 render 中用:
例如:
本质是:
减少需要 hydration 的范围
先看传统 SSR 流程:
Server Render HTML
↓
Browser 接收 HTML
↓
整页 Hydration
↓
页面可交互
问题在于:
页面里很多内容其实根本不需要交互。
例如一个电商详情页:
这些内容:
然而传统 SSR 会做什么?
即使这些内容完全静态,也要执行 hydration。
也就是说:
静态内容 + 动态内容
全部进入 hydration
这就带来两个问题:
例如页面结构:
<div>
Header
ProductInfo
Comments
BuyButton
Footer
</div>
真正需要交互的可能只有:
BuyButton
但传统 hydration:
Header hydrate
ProductInfo hydrate
Comments hydrate
BuyButton hydrate
Footer hydrate
本质上:
为了一个按钮,整页都要重复执行一遍。
这很浪费。
前面说过:
hydration 本质是重复计算
那只要重复计算范围越大:
都会扩大。
整页 hydration 意味着:
整页都有 mismatch 风险。
Islands 架构把页面拆成:
例如:
<Header />
<ProductInfo />
<BuyButton client:load />
<Footer />
只有:
BuyButton
需要客户端接管。
其余部分:
流程变成:
Server Render HTML
↓
静态部分直接展示
↓
仅局部组件 hydration
传统 SSR:
HTML 先渲染,JS 再接管整页
Islands:
HTML 默认静态,只有少数区域需要 JS
所以它的核心思想不是:
“怎么更高效地 hydration”
而是:
尽量少 hydration,甚至不 hydration
这就是为什么说:
Islands 本质是在逃避 hydration。
不是因为 hydration 做得不好,而是因为:
hydration 天然昂贵且天然存在一致性问题。
既然如此,最好的办法不是优化它,而是减少它。
这和传统 SPA 思路完全相反。
SSR 第一阶段在解决:
首屏白屏问题
Hydration 第二阶段在解决:
HTML 如何变成交互页面
而 Islands 的想法是:
并不是所有 HTML 都需要变成交互页面。
所以它直接重新定义问题。
这就是架构升级。
不是:How to hydrate better
而是:How to hydrate less
Hydration mismatch 不是一个“bug”,而是 SSR 架构的副作用。
因为 SSR 本质是让同一段渲染逻辑在两个不同环境执行,而只要存在时间、环境、状态或随机性的差异,就无法保证输出完全一致。
框架要求一致,是为了复用 DOM 提升性能;而不一致,就只能回退到重新渲染。
因此,hydration mismatch 并不是“可以彻底避免的问题”,而是一个需要被工程化控制的问题。
Traditional SSR 的问题不是不能工作,而是默认假设“整页都需要交互”。
但现实中,大部分页面内容本质是静态的。
Islands 架构通过把页面拆分为静态区域和交互区域,只对少量组件执行 hydration。
因此它并不是在优化 hydration,而是在架构层面减少 hydration 的发生范围。
某种意义上,Islands 并不是解决 hydration 的问题,而是在逃避 hydration 本身。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。