岛屿架构 #

一、什么是岛屿架构? #

1.1 传统架构问题 #

text
传统 SPA(单页应用):

┌────────────────────────────────────────────────────┐
│                                                    │
│    整个页面需要水合(Hydration)                    │
│    ████████████████████████████████████████████   │
│                                                    │
│    问题:                                          │
│    • 大量 JavaScript 需要加载                      │
│    • 首屏渲染慢                                    │
│    • 交互延迟                                      │
│    • SEO 困难                                     │
│                                                    │
└────────────────────────────────────────────────────┘

1.2 Islands 架构解决方案 #

text
Astro Islands 架构:

┌────────────────────────────────────────────────────┐
│                                                    │
│    静态 HTML(零 JavaScript)                      │
│                                                    │
│    ┌──────────┐         ┌──────────┐             │
│    │ 交互岛屿 │         │ 交互岛屿 │             │
│    │  🏝️     │         │  🏝️     │             │
│    │ 购物车   │         │ 搜索框   │             │
│    └──────────┘         └──────────┘             │
│                                                    │
│    优势:                                          │
│    • 首屏极快                                      │
│    • 按需加载 JavaScript                           │
│    • SEO 友好                                     │
│    • 优秀的用户体验                                │
│                                                    │
└────────────────────────────────────────────────────┘

二、水合策略 #

2.1 client:load #

页面加载时立即水合:

astro
---
import Counter from '../components/Counter';
---

<!-- 首屏关键交互组件 -->
<Counter client:load />

适用场景:

  • 首屏可见的交互组件
  • 关键功能组件
  • 不依赖其他条件

2.2 client:idle #

浏览器空闲时水合:

astro
---
import Newsletter from '../components/Newsletter';
---

<!-- 非关键交互组件 -->
<Newsletter client:idle />

适用场景:

  • 页面底部的组件
  • 非关键功能
  • 可延迟加载

2.3 client:visible #

进入视口时水合:

astro
---
import ImageGallery from '../components/ImageGallery';
---

<!-- 滚动后可见的组件 -->
<ImageGallery client:visible />

适用场景:

  • 需要滚动才能看到的组件
  • 图片画廊
  • 评论区域

2.4 client:media #

满足媒体查询时水合:

astro
---
import MobileMenu from '../components/MobileMenu';
---

<!-- 仅在移动端加载 -->
<MobileMenu client:media="(max-width: 768px)" />

适用场景:

  • 响应式组件
  • 特定设备功能
  • 条件性交互

2.5 client:only #

跳过服务端渲染,仅在客户端渲染:

astro
---
import BrowserChart from '../components/BrowserChart';
---

<!-- 依赖浏览器 API 的组件 -->
<BrowserChart client:only="react" />

适用场景:

  • 依赖 window/document 的组件
  • 浏览器特定功能
  • 第三方库限制

三、岛屿优化 #

3.1 最小化岛屿 #

astro
---
import StaticContent from '../components/StaticContent.astro';
import InteractiveButton from '../components/InteractiveButton';
---

<div>
  <!-- 静态内容:不需要 JS -->
  <StaticContent />
  
  <!-- 只有交互部分是岛屿 -->
  <InteractiveButton client:load />
</div>

3.2 拆分组件 #

astro
---
// ❌ 不好的做法:整个组件都是岛屿
<Card client:visible>
  <h2>标题</h2>
  <p>静态内容...</p>
  <button>交互按钮</button>
</Card>

// ✅ 好的做法:只有交互部分是岛屿
<Card>
  <h2>标题</h2>
  <p>静态内容...</p>
  <InteractiveButton client:visible />
</Card>
---

3.3 延迟加载 #

astro
---
import HeavyComponent from '../components/HeavyComponent';
---

<div>
  <h1>页面标题</h1>
  
  <!-- 首屏内容 -->
  <p>首屏内容...</p>
  
  <!-- 延迟加载重型组件 -->
  <HeavyComponent client:visible />
</div>

四、性能对比 #

4.1 传统 SPA #

text
加载流程:
1. HTML 下载
2. JS 下载(大量)
3. JS 解析执行
4. 组件渲染
5. 页面可交互

首屏时间:慢
可交互时间:慢

4.2 Astro Islands #

text
加载流程:
1. HTML 下载(完整内容)
2. 页面渲染(立即可见)
3. 按需加载岛屿 JS
4. 岛屿水合

首屏时间:快
可交互时间:快

4.3 性能指标 #

指标 传统 SPA Astro Islands
FCP
LCP
TTI
JS 体积

五、最佳实践 #

5.1 选择正确的指令 #

text
决策流程:

是否需要交互?
├── 否 → 使用 Astro 组件(零 JS)
└── 是 → 需要何时交互?
    ├── 立即 → client:load
    ├── 空闲时 → client:idle
    ├── 可见时 → client:visible
    └── 特定条件 → client:media

5.2 组件设计原则 #

text
1. 静态优先
   - 默认使用 Astro 组件
   - 只有交互部分使用框架组件

2. 最小岛屿
   - 只把交互部分变成岛屿
   - 静态内容保持静态

3. 延迟加载
   - 非首屏组件使用 client:visible
   - 非关键功能使用 client:idle

4. 条件加载
   - 响应式组件使用 client:media
   - 避免不必要的 JS 加载

5.3 实际案例 #

astro
---
// 博客页面示例
import Layout from '../layouts/Layout.astro';
import TableOfContents from '../components/TableOfContents.astro';
import ShareButtons from '../components/ShareButtons';
import CommentSection from '../components/CommentSection';
import Newsletter from '../components/Newsletter';
---

<Layout>
  <article>
    <!-- 静态内容 -->
    <h1>{post.data.title}</h1>
    <Content />
    
    <!-- 分享按钮:立即交互 -->
    <ShareButtons client:load />
    
    <!-- 评论区:滚动后加载 -->
    <CommentSection client:visible />
    
    <!-- 订阅表单:空闲时加载 -->
    <Newsletter client:idle />
  </article>
  
  <!-- 目录:静态 -->
  <TableOfContents headings={headings} />
</Layout>

六、总结 #

岛屿架构核心要点:

text
┌─────────────────────────────────────────────────────┐
│                 岛屿架构要点                         │
├─────────────────────────────────────────────────────┤
│                                                     │
│  🏝️ 核心概念    静态 HTML + 交互岛屿               │
│                                                     │
│  🚀 水合策略    load/idle/visible/media/only       │
│                                                     │
│  ⚡ 性能优势    首屏快、JS 少、体验好               │
│                                                     │
│  📐 设计原则    静态优先、最小岛屿、延迟加载        │
│                                                     │
│  🎯 最佳实践    按需选择指令、拆分组件              │
│                                                     │
└─────────────────────────────────────────────────────┘

下一步,让我们学习 个人博客,通过实战项目巩固所学知识!

最后更新:2026-03-28