🏝️ Islands 架构
什么是 Islands 架构
Islands 架构(岛屿架构)是一种现代前端架构模式,由 Jason Miller 在 2019 年提出。它的核心思想是:页面大部分内容是静态 HTML("海洋"),只有少数交互式组件("岛屿")需要 JavaScript hydration。
💡 核心理念
默认发送静态 HTML,只在需要交互的地方"激活"JavaScript,减少不必要的客户端渲染。
架构演进对比
| 架构 | 特点 | 缺点 |
|---|---|---|
| 传统 MPA | 服务端渲染、每次跳转刷新页面 | 体验差、交互弱 |
| CSR (SPA) | 客户端渲染、无缝跳转 | 首屏慢、SEO 差、JavaScript 负担重 |
| SSR | 服务端渲染、SEO 好 | 服务器压力大、TTI 慢(需要 hydration) |
| Islands | 静态 HTML + 局部 hydration | 需要新框架支持、学习曲线 |
Islands 架构工作原理
1. 服务端渲染
页面在服务端渲染成纯 HTML,不包含任何 JavaScript。
<!-- 服务端返回的 HTML -->
<html>
<body>
<header>
<nav>...静态导航...</nav>
</header>
<main>
<article>
<h1>文章标题</h1>
<p>文章内容...</p>
</article>
</main>
<aside data-island="comments">
<div class="comments">
<p>暂无评论</p>
</div>
</aside>
<script type="module" src="/islands/comments.js"></script>
</body>
</html>
2. 渐进式 Hydration
只有标记为"岛屿"的组件才会加载并执行 JavaScript。
// islands/comments.js
import { render } from 'preact';
import Comments from '../components/Comments';
// 只 hydrate 标记为岛屿的元素
const island = document.querySelector('[data-island="comments"]');
if (island) {
render(<Comments />, island);
}
Islands 架构的优势
| 优势 | 说明 |
|---|---|
| 🚀 更快的首屏 | 无需等待 JavaScript 下载执行,HTML 立即可见 |
| 📦 更小的 JS 体积 | 只加载交互组件的 JavaScript |
| 🔍 SEO 友好 | 完整 HTML 内容,搜索引擎可索引 |
| ♿ 可访问性好 | 无 JavaScript 也能访问核心内容 |
| 💰 服务器成本低 | 大部分内容可 CDN 缓存 |
| 📱 低端设备友好 | 减少 JavaScript 解析执行负担 |
支持 Islands 架构的框架
| 框架 | 语言 | 特点 |
|---|---|---|
| Astro | JavaScript/TypeScript | 框架无关、支持 React/Vue/Svelte 组件、最流行 |
| Fresh | TypeScript | 基于 Deno、零配置、内置 Islands |
| Qwik | TypeScript | 可恢复性(Resumability)、零 hydration |
| Marko | JavaScript | 流式 SSR、细粒度 hydration |
| 11ty + Alpine | JavaScript | 静态站点 + 轻量交互 |
Astro 示例
1. 安装 Astro
# 创建新项目
npm create astro@latest my-islands-app
# 安装 React 集成
npx astro add react
# 启动开发服务器
npm run dev
2. 页面结构
---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Header from '../components/Header.astro';
import ProductCard from '../components/ProductCard.jsx';
import Cart from '../components/Cart.jsx';
---
<Layout title="商店">
<Header /> <!-- 静态 Astro 组件 -->
<main>
<h1>热门商品</h1>
<!-- 交互式 React 组件(Island)-->
<ProductCard client:load />
<ProductCard client:load />
<!-- 仅在可见时加载 -->
<Cart client:visible />
<!-- 空闲时加载 -->
<Analytics client:idle />
</main>
</Layout>
3. 交互指令
| 指令 | 说明 |
|---|---|
client:load |
页面加载时立即 hydrate |
client:idle |
浏览器空闲时 hydrate |
client:visible |
元素进入视口时 hydrate |
client:media |
匹配媒体查询时 hydrate |
client:only |
仅客户端渲染(跳过 SSR) |
Fresh 示例
1. 项目结构
my-fresh-app/
├── routes/
│ ├── index.tsx # 首页路由
│ ├── products/
│ │ └── [id].tsx # 动态路由
│ └── api/
│ └── cart.ts # API 路由
├── islands/
│ ├── Counter.tsx # 交互岛屿
│ └── ProductCard.tsx # 产品卡片岛屿
├── components/
│ └── Header.tsx # 静态组件
└── main.ts # 入口文件
2. 路由文件
// routes/index.tsx
import { Handler } from '$fresh/server.ts';
import Counter from '../islands/Counter.tsx';
export default async function handler(req: Request) {
return (
<>
<h1>欢迎使用 Fresh!</h1>
<!-- 自动作为 Island 处理 -->
<Counter initialCount={0} />
</>
);
}
3. Island 组件
// islands/Counter.tsx
import { useState } from 'preact/hooks';
export default function Counter({ initialCount }: { initialCount: number }) {
const [count, setCount] = useState(initialCount);
return (
<div>
<p>计数:{count}</p>
<button onClick={() => setCount(count + 1)}>
+1
</button>
</div>
);
}
Qwik 的可恢复性
Qwik 提出了"可恢复性"(Resumability)概念,完全消除了 hydration:
<!-- Qwik 生成的 HTML -->
<div
q:container="container"
q:version="1.0.0"
q:state='{"count":0}'
>
<button
q:on:click="handleClick_abc123"
>
点击我
</button>
</div>
// JavaScript 按需加载
// 只有点击时才加载 handleClick 函数
最佳实践
- ✅ 默认静态:除非必要,否则使用静态 HTML
- ✅ 小岛原则:交互组件尽量小且独立
- ✅ 延迟加载:使用
client:visible或client:idle - ✅ 组件通信:使用 Custom Events 或全局状态
- ✅ SEO 优先:核心内容必须是静态 HTML
- ✅ 渐进增强:无 JavaScript 时功能降级但不失效
适用场景
| 场景 | 推荐度 | 说明 |
|---|---|---|
| 内容网站 | ⭐⭐⭐⭐⭐ | 博客、文档、新闻站点 |
| 电商网站 | ⭐⭐⭐⭐⭐ | 产品列表、详情页、购物车 |
| 营销页面 | ⭐⭐⭐⭐⭐ | Landing Page、活动页 |
| SaaS 应用 | ⭐⭐⭐⭐ | Dashboard、管理后台 |
| 实时应用 | ⭐⭐⭐ | 聊天、协作文档(需大量交互) |
| 游戏/创意应用 | ⭐⭐ | 需要持续 JavaScript 运行 |
2026 年新趋势
| 趋势 | 描述 |
|---|---|
| 部分 Hydration | 只 hydrate 组件树中必要的部分 |
| 流式 Islands | Islands 通过流式传输渐进式加载 |
| 边缘 Islands | 在边缘节点渲染和缓存 Islands |
| AI 生成 Islands | AI 自动识别并提取交互组件 |
| 零 JS Islands | 使用 CSS 和 HTML 属性实现简单交互 |