Islands 架構——Astro 的 Partial Hydration 原理
問題的起點
在傳統的 SPA 框架中,頁面渲染的流程是這樣的:
- 伺服器返回一個空的 HTML(或帶有內容的 SSR HTML)
- 瀏覽器下載整個框架的 JavaScript runtime
- 框架執行 hydration —— 為 DOM 元素綁定事件處理器
- 頁面才變得可互動
問題在於:如果頁面上只有一個按鈕需要互動,為什麼要為整個頁面執行 hydration?
Islands 架構的核心思想
Islands 架構將頁面上的互動元素視為獨立的「島嶼」,每個島嶼:
- 擁有自己的 JavaScript bundle
- 獨立載入和初始化
- 不影響周圍的靜態 HTML
島嶼之外的部分是純靜態 HTML,永遠不會被 JavaScript 觸碰。
┌─────────────────────────────────┐
│ 靜態 HTML 標題 │
├─────────────────────────────────┤
│ ┌───────────┐ │
│ │ 🏝️ React │ 靜態內容 │
│ │ 購物車 │ │
│ └───────────┘ │
├─────────────────────────────────┤
│ ┌───────────┐ │
│ │ 🏝️ Vue │ │
│ │ 搜尋欄 │ 靜態文字 │
│ └───────────┘ │
└─────────────────────────────────┘
Astro 中的實現
在 Astro 中,你使用 client:* 指令來控制組件何時載入 JavaScript:
<!-- 靜態:完全在伺服器渲染,不發送 JS -->
<MyComponent />
<!-- 頁面載入後立即 Hydrate -->
<MyComponent client:load />
<!-- 進入可視區域時 Hydrate -->
<MyComponent client:visible />
<!-- 瀏覽器空閒時 Hydrate -->
<MyComponent client:idle />
<!-- 媒體查詢匹配時 Hydrate -->
<MyComponent client:media="(min-width: 768px)" />
<!-- 僅在與該元素互動時 Hydrate -->
<MyComponent client:only="react" />
與 React Server Components 的對比
React Server Components(RSC)和 Astro Islands 看似相似,但理念不同:
| 對比維度 | Astro Islands | React Server Components |
|---|---|---|
| 框架鎖定 | 多框架(React/Vue/Svelte/Solid) | 僅 React |
| 互動粒度 | 組件級別 | 組件級別 |
| 傳輸協議 | 客戶端 JavaScript bundle | 串流 JSON + 客戶端 React |
| 靜態內容 | 純 HTML,零 JS | 需串流客戶端 React runtime |
| 學習曲線 | 低,接近 HTML | 需理解 Suspense、use client 等概念 |
為什麼這很重要?
效能測試顯示,對於內容網站:
- 減少 50-90% 的 JavaScript 傳輸量
- First Contentful Paint(FCP)平均降低 40%
- Time to Interactive(TTI)平均降低 60%
數據背後的原因很簡單:JavaScript 是當今網頁效能的最大瓶頸。下載、解析和執行 JS 都需要時間,在移動設備上尤其明顯。
何時使用哪種策略
<!-- 首屏以上、關鍵互動 → client:load -->
<Header client:load />
<!-- 折疊以下 → client:visible -->
<Comments client:visible />
<!-- 非關鍵 → client:idle -->
<AnalyticsDashboard client:idle />
<!-- 純靜態 → 不加任何指令 -->
<ArticleContent />
結語
Islands 架構不是一個全新的概念,但 Astro 把它落實到了實用層面。它讓開發者可以精確控制 JavaScript 的載入策略,而不需要為此學習一套複雜的系統。對於內容為主的網站來說,這可能是目前最合理的架構選擇。