提到前端的渲染架構,最常聽到的就是 CSR、SSR、SSG 三個名詞。它們對網站效能的影響相當顯著,但「SSR 一定比 CSR 快」這類說法其實太過絕對。本章重新梳理這幾種主流架構,順便看看相對年輕的 ISR 解決了哪些問題。
客戶端渲染(CSR, Client-Side Rendering)#
在 React、Vue、Angular 等框架普及後,SPA(Single-Page Application)成為主流。HTML 通常只放一個容器:
<html>
<head></head>
<body>
<div id="root"></div>
<script src="./script.js"></script>
</body>
</html>整個流程是:
- 伺服器回傳只有容器的 HTML。
- 瀏覽器下載並執行 JavaScript bundle。
- JavaScript 動態渲染元素並建立互動性。
CSR 的好處是換頁不會反白、後端壓力小,但會帶來兩個明顯問題:
- SEO 問題:爬蟲拿到的 HTML 是空殼。
- 效能與體驗問題:使用者必須等到 JS 載入並執行完才能看到內容。Bundle 過大時更明顯。
要緩解 SEO 問題,可以在 Web Server 偵測爬蟲並回傳預先渲染好的 HTML,或在邊緣節點(例如 Lambda@Edge、Cloudflare Workers)做 pre-rendering。
伺服器端渲染(SSR, Server-Side Rendering)#
過去的網頁普遍是傳統 SSR:伺服器處理完資料後組裝完整的 HTML 回傳。優點是頁面與資料一起送到、SEO 友善;缺點是換頁會閃爍、伺服器要做的事多。
現代我們講的 SSR 多半是 Isomorphic SSR(混合式 SSR)。流程是:
- 伺服器先渲染出帶有資料的 HTML,回傳給瀏覽器。
- 瀏覽器下載 JS 並做 hydration,把伺服器產出的 DOM 「補上」事件監聽器,使其具備互動性。
相比 CSR,使用者能更早看到畫面、SEO 也得到改善。但缺點是:
- 必須維護一台 rendering server(通常為 Node.js)。
- 程式碼要同時考量 server 與 client 兩個執行環境。
- 在大流量下,rendering server 容易成為瓶頸。
靜態網站生成(SSG, Static Site Generation)#
SSG 在 build time 就把完整的 HTML 生出來,後續所有請求都共用同一份檔案。這也常被稱作 pre-rendering。
優點:
- 三者中效能最好的方案。
- 適合放到 CDN,享受邊緣快取。
- 對 SEO 完全友善。
缺點:
- 內容變動就要重新 build。
- 網站越大,build time 越長。
- 不適合需要即時或頻繁更新的內容(例如電商商品頁)。
增量靜態再生成(ISR, Incremental Static Regeneration)#
ISR 是 Next.js 9.5 提出的混合策略,介於 SSR 與 SSG 之間,特別適合「頁面很多但更新沒那麼頻繁」的情境。它的運作方式是:
- 第一次請求某個頁面時,先回傳 fallback(例如 skeleton)。
- 同時在伺服器端抓取資料、產生完整頁面,並丟到 CDN 快取。
- 後續對相同頁面的請求直接命中 CDN,跟 SSG 一樣快。
- 透過
revalidate設定快取的有效時間,過期後在背景重新產生。
export async function getStaticProps() {
const res = await fetch("https://...");
const data = await res.json();
return { props: { data }, revalidate: 60 };
}實務參考 ISR 採用的快取策略稱作 stale-while-revalidate:先回傳舊版本,再在背景更新,使用者體驗與資源消耗都比較平衡。
Streaming SSR 與 Progressive Hydration#
傳統的 Isomorphic SSR 還是有幾個瓶頸:
- 必須等所有 API 資料抓齊才能組 HTML。
- 必須載入完所有 JavaScript 才能 hydration。
- 必須 hydration 完所有元件,頁面才能互動。
Streaming SSR 讓伺服器以 chunk 的方式逐步輸出 HTML,瀏覽器可以漸進地拿到內容,FP 與 FCP 都會更快。Progressive Hydration 則讓部分元件先具備互動性,不必等整個頁面 hydrate 完。React 18 的 Suspense SSR 就是基於這個方向設計。
各架構對效能指標的影響#
評估時通常會看以下幾個指標:
- Time to First Byte (TTFB):發出請求到拿到第一個 byte 的時間。
- First Paint (FP):首次有任何像素被繪製的時間。
- First Contentful Paint (FCP):首次顯示文字或圖片的時間。
- Time to Interactive (TTI):頁面從不能互動變得可以互動的時間。
各架構的特性可以這樣對應:
- 傳統 SSR:FP / FCP / TTI 較好,但 TTFB 較久。
- CSR:JS bundle 過大時 FCP 與 TTI 都會被拖慢。可以用程式碼分割、Lazy Loading、preload、HTTP/2 等手段緩解。
- SSG:靜態內容 + CDN,整體指標最佳。
- 混合式 SSR:FCP 比 CSR 好,但 hydration 會拉長 TTI。建議只在 server 處理對 SEO 重要的資料。
該如何選擇#
實話實說:It depends。
- 重度互動但 SEO 不那麼重要:CSR 仍是合適的選擇。
- 需要 SEO 與動態資料:考慮 SSR。但 server side 不要扛太多計算。
- 內容變動低、追求極致效能:SSG。
- 頁面很多但更新頻率介於中間:ISR。
幸好像 Next.js 這類框架都已支援 page-level 的渲染策略:同一個專案中,不同頁面可以分別走 CSR、SSR、SSG 或 ISR,依需求自由搭配。
小結#
每一種渲染架構都有自己的甜蜜點,不該套用「總是 SSR 最快」之類的單一規則。理解各方案的取捨後,再針對頁面的內容特性、更新頻率與 SEO 需求做決策,網站的效能與維護成本才能取得平衡。