Astro 系列(三):Island 架构——为什么默认零 JavaScript
Astro 入门与实战 系列导航
水合作用:为什么它是问题
水合(Hydration)是服务端渲染框架的核心机制:服务端生成 HTML,客户端下载 JavaScript 后,React/Vue 遍历每个 DOM 节点,绑定事件监听器、初始化状态,让静态 HTML "活过来"。
这个过程的问题在于:
- CPU 消耗:每个组件都要执行水合,即使它没有交互
- 阻塞渲染:水合是同步过程,期间用户无法交互
- 浪费带宽:下载了大量 JS,但大部分组件的功能用户根本用不到
对于一个博客文章页面来说,除了评论区和导航菜单,99% 的 DOM 节点不需要任何交互。但传统的 SSR 框架会对整个页面进行水合。
岛屿架构:只激活需要交互的部分
Astro 的方案是把页面看作"静态海洋 + 交互岛屿":
- 页面主体(海洋)是纯 HTML,永远不会被水合
- 交互组件(岛屿)独立加载、独立水合
- 岛屿之间互不干扰
这使得性能显著提升:
- JS 体积:只传输需要交互的组件代码
- 水合开销:只执行需要交互的组件的水合
- 并行性:多个岛屿可以并行水合,不互相阻塞
client 指令:控制岛屿的激活时机
Astro 提供了五个 client:* 指令来控制组件何时激活:
client:load — 页面加载后立即水合。适用于高优先级交互组件,如导航栏、购物车按钮。
client:idle — 浏览器空闲时水合。适用于次要交互组件,如反馈按钮、分享面板。它利用 requestIdleCallback,不影响首屏性能。
client:visible — 组件进入视口时水合。适用于页面下方的交互组件,如下拉加载、底部表单。它是懒加载 + 按需水合的结合。
client:media — 匹配媒体查询时水合。适用于响应式组件,如移动端菜单——桌面端根本不需要。
client:only — 跳过服务端渲染,仅在客户端渲染。适用于依赖浏览器 API 的组件,如使用 localStorage 或 window 对象的组件。
每个指令背后是对"何时需要交互"这个问题的精确回答。默认行为(不加指令)是永不水合——组件在服务端渲染成纯 HTML,不发送任何 JS。
多框架混用:BYOF 的真正威力
Astro 不捆绑任何 UI 框架。你可以在同一个项目中:
- 用 React 写评论区(生态成熟、第三方库多)
- 用 Svelte 写图表组件(轻量、性能好)
- 用 Vue 写表单(渐进式增强方便)
- 用 Solid 写实时数据面板(细粒度响应式)
每个框架组件都是独立岛屿,有自己的水合时机和 JS bundle。这种"微前端"式的组合在过去需要复杂的配置,在 Astro 中是默认行为。
岛屿架构的边界
不是所有场景都适合岛屿架构:
- 组件间需要频繁通信(如拖拽排序列表)——跨越岛屿的通信成本高
- 需要全局状态管理(如 Redux store 跨页面)——岛屿之间天然隔离
- 纯 SPA 应用(如在线文档编辑器)——几乎所有内容都需要交互
这些场景更适合 Next.js App Router 或 SvelteKit 的全量水合模式。
延伸阅读
实操清单
- 在 Astro 项目中创建一个 React 或 Vue 组件
- 分别尝试
client:load、client:idle、client:visible,观察浏览器 DevTools 中 JS 加载时机的差异 - 用 Lighthouse 对比加和不加
client:load的页面性能 - 思考自己项目中有哪些组件其实不需要 JS
created by:codex on deepseek v4 pro