局部水合和 Islands Architecture 为什么能改善首屏性能?
简化版
传统 SSR 页面虽然 HTML 出得快,但如果整页都要水合,浏览器仍要下载大量 JS、执行框架运行时并绑定事件。局部水合和 Islands Architecture 的思路是:静态内容只输出 HTML,只有真正需要交互的组件才加载 JS 和水合,从而减少首屏 JS、主线程任务和交互延迟。它适合内容站、营销页、文档站和交互区域相对独立的页面。
详细版
水合性能问题来自“HTML 已经可见,但 JS 还在接管页面”。如果页面大部分是静态内容,整页水合会浪费。
| 模式 | JS 范围 | 优点 | 代价 |
|---|---|---|---|
| CSR | 整页由 JS 渲染 | 交互灵活 | 首屏依赖 JS |
| SSR 全量水合 | 整页下载并绑定 | 首屏 HTML 快 | 水合成本高 |
| 局部水合 | 只水合交互组件 | JS 少、主线程轻 | 架构约束更强 |
| Islands | 多个交互岛独立加载 | 按需交互 | 状态共享要设计 |
<ArticleContent />
<CommentBox client:visible />
<LikeButton client:idle />
局部水合的目标不是不要 JS,而是让 JS 只出现在真正需要交互的地方。
完整版教学
一、SSR 为什么仍可能慢
SSR 能让服务端先输出 HTML,用户更早看到内容。但现代框架页面通常还要在客户端水合:下载 JS、解析执行、恢复组件树、绑定事件。
如果页面中 80% 是静态内容,仍然为整页下载和执行 JS,就会浪费带宽和主线程时间。
二、什么是局部水合
局部水合是只让部分组件在客户端变成可交互状态。静态区域保持 HTML,不加载对应组件 JS。
比如文章正文、标题、面包屑可以是纯 HTML;点赞按钮、评论框、搜索框才需要客户端 JS。
三、Islands Architecture 的思路
Islands Architecture 把页面看成静态海洋中的多个交互岛。每个岛可以独立加载、独立水合。
常见加载策略包括:
- 可见时加载。
- 浏览器空闲时加载。
- 用户交互时加载。
- 首屏关键交互立即加载。
四、为什么能改善性能
它减少三类成本:
| 成本 | 改善方式 |
|---|---|
| 网络成本 | 少下载不需要的组件 JS |
| 解析执行 | 少执行框架和业务代码 |
| 主线程阻塞 | 少做组件恢复和事件绑定 |
这对 LCP 和 INP 都可能有帮助,尤其是内容站和营销页。
五、适用场景
适合:
- 文档站、博客、资讯页。
- 电商详情页中的局部交互。
- 营销落地页。
- SEO 重要、交互较少的页面。
不适合强应用型页面,例如复杂在线编辑器、后台管理系统和高度共享状态的实时协作页面。
六、工程挑战
局部水合会带来新的工程问题:
- 交互岛之间状态共享变复杂。
- 全局 store 不能随意假设整页都在客户端运行。
- 第三方组件如果依赖浏览器 API,需要隔离。
- 水合时机不当可能导致用户点击时组件还没准备好。
// 设计交互岛时,优先通过 URL、表单、轻量事件或服务端状态解耦
document.dispatchEvent(new CustomEvent('cart:update', { detail: { count: 3 } }))
七、常见误区与追问
- 误区:SSR 一定性能好。 SSR 只解决 HTML 生成和 SEO 问题,客户端水合仍可能很重。
- 误区:局部水合适合所有 SPA。 强交互应用可能因为状态共享和交互延迟变复杂。
- 误区:少 JS 就没有性能问题。 图片、字体、CSS、TTFB 和第三方脚本仍然可能拖慢页面。
- 追问:它和懒加载组件有什么区别? 懒加载仍可能在 CSR 应用中运行,局部水合强调静态 HTML 和交互岛分离。
- 追问:哪些组件应该立即水合? 首屏可见且用户可能马上操作的关键交互组件。
- 追问:如何避免点击时还没水合? 对关键控件立即加载,非关键控件用 visible 或 idle,并提供可用的降级状态。
八、加强记忆
局部水合记成“静态归静态,交互归交互”。SSR 先给 HTML,Islands 只给需要交互的区域加载 JS;它能减少首屏 JS 和主线程水合成本,但要认真设计状态边界。