跳轉到

3.1 Jamstack 與靜態優先架構:為什麼快取是最好的後端#

本節目標#

在動手架站之前,先回答一個根本問題:現代網站為什麼要「靜態優先」? 本節回顧從 CGI 到動態頁的歷史、Jamstack 的誕生脈絡,說明「預先建置 + 邊緣快取」為何在延遲、成本與安全性上都勝過每次請求都現做的傳統架構,最後以對照表釐清靜態生成(SSG)與伺服器端渲染(SSR)的差異,為第 3.2、3.3 節的實作鋪路。

歷史:從 CGI 到動態頁的代價#

Web 最初的形態極其簡單:伺服器上放一堆 .html 檔,請求來了就原樣回傳。1993 年 CGI(Common Gateway Interface)問世,讓網頁能「現場產生」——每個請求 spawn 一個處理程序跑 Perl 腳本、查資料庫、拼出 HTML。

CGI 時代(1993-):
瀏覽器 → Apache → fork() 處理程序 → 執行 Perl/PHP → 查 DB → 拼 HTML → 回傳

這開啟了動態 Web(留言板、購物車),但也埋下三個代價:

  1. 延遲:每次請求都要現場運算,使用者等的是「伺服器的翻譯時間」。
  2. 成本:伺服器必須常駐、隨流量擴容;沒人看時資源照樣燒錢。
  3. 攻擊面:動態程式碼直接暴露在公網,SQL Injection、RCE 都發生在這一層。

此後三十年,架構史可粗略濃縮為一句話:把「現做」推回「先做好」,把運算從中心推到邊緣。

年代 形態 關鍵字
1993 CGI / 動態頁 每請求現做
2005 快取層(Squid、Varnish、Memcached) 把熱門頁「記住」
2010s CDN 普及 快取推到全球邊緣
2016 Jamstack 連建置都提前完成:部署即靜態

Jamstack 詞源:JavaScript、APIs、Markup#

2016 年,Netlify 執行長 Mathias Biillmann 與創辦人系統性地命名了這股潮流——Jamstack:

JavaScript + APIs + prebuilt Markup,無需自管 Web 伺服器。

核心主張只有一條公式:

\[ \text{頁面} = \text{建置時完成的 Markup} + \text{瀏覽器端 JS 增強} + \text{隨選 APIs(資料與動作)} \]

注意 stack 不是技術棧,而是「分層拆開」的意思:Markup(視圖)、JS(互動)、APIs(資料)三層各自獨立演化、各自快取。動態的部分不是不存在,而是被推到兩端——前端交給瀏覽器執行,資料交給 API(在我們的書中,就是稍後的 Pages Functions 與 Workers)。

為何快取優先:三條數學上的勝利#

延遲:CDN 邊緣節點離使用者往往 <50ms,而回源到中央伺服器再運算常 >300ms。快取命中時:

\[ T_{\text{總}} = T_{\text{RTT(邊緣)}} \quad \text{vs} \quad T_{\text{總}} = T_{\text{RTT}} + T_{\text{運算}} + T_{\text{DB}} \]

成本:靜態檔案由邊緣以近乎零邊際成本服務,不需要為「深夜的十個訪客」養一台 24 小時伺服器。

安全:公網上沒有可執行的伺服器程式碼,就沒有可攻擊的伺服器程式碼——攻擊面只剩靜態檔案與你「主動提供」的 API 端點。

不可變部署:快取能大膽的前提#

Jamstack 能放心「永久快取」,靠的是內容定址(content-addressable)的檔名:

/assets/index.a8f3c1.js    ← 檔名含內容雜湊,內容一變檔名就變

於是「更新網站」從「修改伺服器上的檔案(快取全部作廢)」變成「部署一批全新檔名的新檔案(舊快取永遠有效)」。Cloudflare Pages 在 3.4 節會看到,它把每個部署整個凍結成不可變的版本目錄,正是這個理念的產品化。

靜態優先與 Islands Architecture#

「靜態優先」不是「全部靜態」,而是預設靜態、按需注水:

┌──────────────────────────────┐
│  99% 是純 HTML/CSS(島的海洋) │
│  ┌────┐          ┌────┐      │
│  │島1 │  靜態海   │島2 │      │
│  │搜尋│          │留言│      │
│  └────┘          └────┘      │
└──────────────────────────────┘

Islands Architecture(群島架構):整頁是伺服器預先渲染好的靜態 HTML;只有少數需要互動的元件(島)單獨載入 JS 並「注水(hydrate)」。頁面上沒有互動的部分零 JS、零水合成本 —— 這是 Astro 的核心設計(3.2 節將實際使用)。

靜態生成 vs 伺服器端渲染#

面向 SSG(Static Site Generation) SSR(Server-Side Rendering)
何時產生 HTML 部署/建置時,一次性 每個請求,現場運算
執行位置 CI 機器(建一次) 每台伺服器/邊緣運算
邊緣快取 天然可快取、永久有效 需 TTL 與失效策略
資料新鮮度 建置那一刻的快照 永遠最新
延遲 最低(純 CDN 命中) 較高(運算 + 可能查 DB)
成本 幾乎為零 隨流量線性成長
適合 文件、部落格、行銷頁、作品集 搜尋、個人化 Feed、結帳頁

本書的取捨原則:能靜態就靜態,動態資料用 API 補。部落格文章是建置時從 Git/Markdown 生成的靜態頁(SSG);留言、點讚這類即時資料,由瀏覽器呼叫邊緣 API取得——兩全其美,且完全跑在 Cloudflare 免費方案內。

小結與練習#

本節確認了靜態優先的理論根基:CGI 以來的動態代價(延遲、成本、攻擊面)催生了 Jamstack——把 Markup 提前建置、把互動留在瀏覽器、把資料推給 API,讓全球邊緣快取成為最好的「後端」。

練習

  1. 打開任一你常逛的大型網站,用開發者工具 Network 面板觀察:HTML 是 server-rendered 還是 CDN 快取的靜態檔?哪些資源是請求後才由 JS 載入的「島」?
  2. 把「留言板」用本節的公式拆解:哪些屬於 prebuilt Markup?哪些屬於瀏覽器 JS?哪些屬於 API?
  3. 思考題:若一個頁面每分鐘資料都在變(股價頁),Jamstack 還適用嗎?提示:增量靜態再生成(ISR)、短 TTL 快取與純 SSR 各有何取捨?

下一節動手建立前端專案。