局部水合和 Islands Architecture 是什么?它们如何降低 SSR 页面成本?
简化版
局部水合是指 SSR 页面并不是把整棵组件树都变成可交互,而是只让真正需要交互的组件加载 JavaScript 并完成 hydration。Islands Architecture 可以理解为“静态 HTML 海面上有多个交互岛屿”:文章正文、导航文本、静态卡片可以直接作为 HTML 输出,评论框、筛选器、购物车按钮这类交互区域再按需加载客户端脚本。
详细版
传统 SSR 容易出现“HTML 很快到达,但 JS 很重”的问题。用户先看到页面,随后浏览器仍要下载、解析、执行一大包 JavaScript,并把整页组件树水合起来。如果页面大部分内容其实不需要交互,全量水合就是浪费。
局部水合的核心收益是减少首屏 JavaScript、降低主线程压力、缩短可交互时间。它通常配合组件级懒加载、按视口加载、按事件加载、服务端组件或静态组件一起使用。
面试回答时不要只说“性能更好”,要说明它解决的是 SSR 的客户端运行时成本,而不是服务端渲染 HTML 的成本。
完整版教学
一、先说明它解决的矛盾
SSR 的优势是首屏 HTML 和 SEO,但它不等于天然轻量。
很多 SSR 框架会在客户端重新加载同一套组件逻辑,用 hydration 把服务端 HTML 接管成可交互应用。
如果页面 80% 是静态内容,仍然全量水合,就会把“静态内容”也纳入客户端 JavaScript 成本。
局部水合的目标就是把交互边界变小。
面试里可以把它讲成:SSR 解决“先看到”,局部水合解决“少执行、快交互”。
二、Islands Architecture 的直观模型
页面整体由服务端输出 HTML。
默认内容是静态的,不绑定客户端运行时。
只有声明为 island 的组件才会加载浏览器端 JavaScript。
每个 island 可以独立加载、独立水合、独立失败降级。
这让内容型网站、营销页、文档站、电商详情页非常适合使用 islands 思路。
三、和传统全量 hydration 的区别
| 维度 | 全量 Hydration | 局部水合 / Islands |
|---|---|---|
| JS 范围 | 整个页面组件树 | 只有交互组件 |
| 首屏 HTML | 快 | 快 |
| 可交互成本 | 可能较高 | 通常更低 |
| 失败影响 | 可能影响整页接管 | 单个岛屿可降级 |
| 适合场景 | 强交互应用 | 内容为主、局部交互 |
四、常见加载策略
局部水合不是只有一种触发方式。
可以页面加载后立即水合关键按钮。
可以等组件进入视口后再水合评论区。
可以等用户点击、悬停、聚焦时再加载搜索框逻辑。
也可以在浏览器空闲时补齐次要交互。
五、代码层面的表达
不同框架 API 不同,但思路类似:把交互组件显式标记为客户端组件或懒加载组件。
// 伪代码:正文在服务端输出,筛选器作为客户端交互岛屿
export default function ProductPage({ products }) {
return (
<main>
<StaticHeader />
<ProductDescription />
<ClientOnlyFilter initialProducts={products} />
</main>
);
}
关键点不是语法,而是把“需要状态和事件”的部分圈出来。
六、设计时要关注边界
交互岛屿不能随便切。
如果两个岛屿之间需要强共享状态,拆得太碎会带来通信复杂度。
如果一个组件虽然小,但依赖很重,也要关注它引入的三方库体积。
如果首屏关键操作依赖某个 island,要保证它优先加载。
七、面试常见误区和追问
- 误区:SSR 之后页面就一定可交互。 SSR 只输出 HTML,可交互还依赖客户端脚本和水合过程。
- 误区:局部水合等于懒加载组件。 懒加载关注加载时机,局部水合关注哪些组件需要客户端接管。
- 误区:Islands 只适合静态站。 它也可以用于动态 SSR 页面,只是内容型页面收益更明显。
- 追问:局部水合会不会影响 SEO? 通常不会,因为主要内容仍由服务端 HTML 输出,交互脚本只是增强体验。
- 追问:怎么判断一个组件应该成为 island? 看它是否需要浏览器状态、事件、DOM API 或实时交互。
- 追问:拆太多 island 有什么问题? 请求数、状态同步、加载顺序和调试复杂度会上升。
八、落地判断口径
适合局部水合的页面通常是内容多、交互少、SEO 重要、首屏性能敏感。
如果是后台系统、在线编辑器、IM 这类强交互应用,全量客户端应用未必更差。
面试可以强调:架构选择要看页面交互密度,而不是看到 SSR 就默认追求 islands。