iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0
Modern Web

手刻部落格,從設計到部署的實戰攻略系列 第 11

Astro(一):輕又快的靜態網站產生器,淺談島嶼架構

  • 分享至 

  • xImage
  •  

我們在前幾講討論 SSG(Static Site Generator)時比較了許多知名的 SSG,包含入門較為簡單的 Jekyll、Hexo,追求效能的 Hugo、Astro,以及需要高互動性的 Gatsby、Next.js 等等。

一切端看我們建立的網站需求為何,我主要的訴求是閱讀居多、搭配少量互動(可參閱我的 PRD),並由於較為熟悉 Node.js 生態,因此最後挑了 Astro 這套 Framework 來作為開發部落格的 SSG,這講就來正式開始介紹 Astro 吧!

Fast By Default

Astro 是一套「內容導向、Server-first」的網站框架,也就是先在伺服器把頁面產好再丟給前端的瀏覽器(同時支援 SSR 及 SSG)。

和多數以 SPA(Single Page Application)為主的框架不同,Astro 不會第一次就載入較大的 JavaScript Bundle,而是預設傳送純 HTML,有互動元件才會將「部分」相關的 JavaScript 傳送給瀏覽器。

只有加上 client:* 的指令,Astro 才會自動將此元件綁定相關的 JavaScript,其餘內容仍是完全沒有 JavaScript 的靜態。下面的例子中 <h1 /> 標籤為靜態,只有和 <Counter /> 相關的 JavaScript 才會被打包起來。

---
// index.astro
import Counter from '../components/Counter.tsx';
---
<h1>Hello Astro</h1>
<Counter client:visible />

*Astro 範例程式

因此 Astro 標榜 Fast by default,據其官網聲稱,Astro 相較於傳統的 React Framework 做出同樣的網站,載入速度快 40%,JavaScript 少 90%。

我們知道從伺服器傳到前端的檔案大小越小,自然傳輸速度也就越快;加上 JavaScript 的量也少,瀏覽器需要執行的腳本少了之後,整體的效能就提高了。

由於網站效能高的緣故,在 SEO 的評分上較其他框架有優勢,也很適合作為部落格、行銷網站或電商平台使用。

島嶼架構(Islands Architecture)

Astro 之所以能讓前端載入少量的 JavaScript,是因為引入了他們參與設計的架構:Islands Architecture,可翻譯成島嶼架構、孤島架構,或是小島架構。

島嶼架構的核心概念是將頁面需要互動的區塊做成一座座獨立的島嶼,當瀏覽器載入頁面之後,才選擇性的 Hydrate(將 DOM 與 JavaScript 綁定)這些小島,藉此達成執行更少的 JavaScript 達到必要的互動

且看一個極簡的頁面,包含標題等靜態內容,以及一個可以往上加的計數器(黃色部分,按鈕加上文字框)。

簡易計數器範例

*簡易計數器範例

Astro 支援 React / Vue / Svelte 等等,這裡就用 React 來做一顆計數器小島。

import { useState } from "react";
export default function Counter() {
  const [n, setN] = useState<number>(0);
	return (
	  <div>
	    <input type="number" value={n} />
	    <button onClick={() => setN(n + 1)}>+</button>
	  </div>
	);
}

Counter.tsx

我們實作了一個很簡單的計數器,這會是頁面中唯一的互動元件,需要使用到 JavaScript 。

---
import Counter from "../components/Counter.tsx";
---
<h1>簡易計數器</h1>
<a href="/">回到首頁</a>

<Counter client:visible />

index.astro

Astro 在產出頁面的時候,會將 <Counter /> 渲染成純 HTML,並包在 <astro-island /> 的自訂元素中,如果有 Props 的話,會在其中加入一段 type="application/json" 的序列化資料,供 Hydration 使用。下方是示意程式碼

<astro-island hydration="visible"
              component-url="/_astro/Counter.[hash].js"
              component-export="default"
              renderer-url="/_astro/react.[hash].js">
  <div>
    <input type="number" value="0" />
    <button>+</button>
  </div>
  <script type="application/json">{}</script>
</astro-island>
<script type="module" src="/_astro/client/[hash].js"></script>

此時 <Counter /> 已經顯示出文字框和計數按鈕,但是還沒辦法真的互動。

下一步,此元件島嶼由於瀏覽器的 Observer 監看 hydration="visible" 的小島,當小島進入視窗可見區的時候會觸發事件,下載此元件的 Bundle,也就是在 component-url 所記錄位置的 JavaScript 檔。

最後一步則是 Hydration,將載入的 JavaScript 和 <astro-island /> 綁定,此時按鈕就可以點擊,成功執行計數的功能了。

參考資料

  1. Astro - Why Astro?
  2. Astro - Islands Architecture

上一篇
設計(五):建構會重複使用的元件
下一篇
Astro(二):初始化專案,理解 Astro Components 及 Layouts 基礎
系列文
手刻部落格,從設計到部署的實戰攻略19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言