什麼是 CSR 與 SSR?
CSR (Client Side Render, 客戶端渲染) 是一種將網頁渲染邏輯交由瀏覽器執行的模式,通常用於 SPA (單頁應用程式)。伺服器僅回傳一個空白 HTML 殼層與 JS bundle,由瀏覽器動態生成內容,具備切換流暢、降低伺服器負擔的優點。SSR (Server Side Render, 伺服器端渲染) 則是由伺服器在接收請求時,先將資料填入模板產出完整的 HTML 再回傳給瀏覽器。SSR 雖然會增加伺服器壓力,但能顯著提升「首屏載入速度」並對「SEO 搜尋引擎優化」極其友善。現代框架如 Next.js 常結合兩者優點,提供包含靜態生成 (SSG) 在內的多樣化渲染策略。
前後端分離或是在一起間接影響網頁渲染的方式,常見的渲染形式會有客戶端渲染 (Client Side Render, CSR) 和伺服器端渲染 (Server Side Render, SSR) 兩種。本篇 React 網頁渲染模式 將深入探討這兩種模式。
這就好像男女朋友是否同居一樣,會大大影響兩人的日常生活型態,分開時兩者的自由度都較高,在一起同居時總會需要考慮彼此狀態。
前後端要分離或是在一起?渲染的方式該怎麼決定?小編覺得也各自有各自的優缺點,接下來就來開箱 CSR 跟 SSR 吧。
Client Side Render (CSR):單頁應用程式的渲染模式
隨著瀏覽器的效能變好,帶有顯示邏輯的渲染可以轉移到瀏覽器端,於是也就出現單頁應用程式 (Single Page Application, SPA) 與 Client Side Render (CSR) 的概念。
在 SPA 中畫面中元素不再直接產生在頁面中,初始時需要 CSR 的部分會是空白的,改由透過 API 要回來的資料和 bundle 檔在前端動態產生渲染畫面。
舉個簡單的例子來說,登入之後不需要跳轉至新的頁面並重新載入,只需要透過要回來的資料來更改網頁中的元素或元件即可。
- 優點:
- 操作體驗較接近真實 App,頁面間切換速度極快。
- 伺服器端壓力較小。
- 缺點:
- 第一次載入時間較慢,但可以透過 Code Splitting 優化。
Server Side Render (SSR):提升首頁載入速度與 SEO
Server Side Render (SSR) 的核心概念是 HTML 由 Server 端產生,所以用戶看到的就是最終版 HTML。SSR 對於提升首頁載入速度和 SEO 尤為重要。SSR 有三種預渲染形式:
- 靜態生成 (Static Generation):透過 Pre-rendering 工具預先渲染頁面產生靜態檔,HTML 在編譯階段就會生成。以小編的部落格來說就是將 Markdown 語法編譯成 HTML 的靜態檔案,在用戶請求之前頁面就已經準備並可被快取。這種渲染方式也可以跟 CSR 搭配著使用來加入額外資訊。
- 伺服器端渲染 (Server Side Render):在每次用戶請求時,會動態生成 HTML。效能上會比靜態生成慢,像大家常用的 WordPress 預設就是這種情況。
- 增強型伺服器端渲染 (Incremental Static Regeneration):定期重新進行 SG 避免頁面沒有抓到較新資訊的問題。
註:Pre Render 這類外掛適用於 CRA 專案但可能會跟不上 React 新功能所產生的問題。
- 優點:
- 第一次載入時間較快。
- 在 CSR 沒特殊設計的情況下 SEO 較佳。
- 缺點:
- 操作體驗較 CSR 差。
- 伺服器壓力較大。
SPA 伺服器端渲染
由於網頁需等待 Bundle 完整載入後才會渲染,速度較慢即使透過 Code Splitting 去把程式碼和用到的函式庫分離開來,但仍然沒有 SSR 產生來的快速。
目前非所有搜尋引擎都能爬取 SPA 中的內容,所以理想狀況是第一頁在伺服器先進行靜態生成或伺服器端端渲染:
- 前端不需等待向後端取得資料的時間 (ex 熱門購物清單)。
- SPA 在操作上不會有整個頁面重新刷新的問題。
Server Side Render 常見問題
伺服器端較簡易的實作方式是用 Node.js 語法來撰寫,理論上前端用到的套件幾乎在後端都會再用到,在實作伺服器渲染時可能會遇到的問題:
- 由於 SPA 是由狀態來決定元件的顯示,那伺服器端的狀態該如何決定呢?
- 後端渲染出來的會不會和前端渲染出來的有差異?RWD?
- 如果有使用狀態管理的函式庫像是 Redux 需要特別處理嗎?
- 前端 SPA 用的路由會影響嗎?
- 伺服器端 Bundle Size 變大。
渲染時 React 會幫我們確認元素的 checksum 是否相同,若不同就會在 client 端重新渲染一次。
前端有用到像是 window.innerWidth 去做條件渲染時會有問題,因為 Server 沒有這些東西,必須等到元件 mount 後,意謂著不可以利用這些物件來做條件渲染,不正確的狀態或是沒考慮過的操作都會讓 checksum 有錯誤,要特別謹記。
後端做 Redux 的 SSR 會搭配初始狀態加上計算後的資料產生 Store 並渲染,接著在 renderToString 時把元件轉成 HTML 字串並整合狀態,前端收到後再重新產生 store 傳入 App 中。
若要減少 Server-side bundle 大小來爭取執行速度時,webpack 的 external 要設定,其他要注意的大概是 webpack target: node 跟 libraryTarget: commonjs2。
套件們使用時需要注意的事項:
- React Router:若有用到 router 的部分不管是前後端都要使用 match 來避免前後端不一致。
- React-Helmet:按照文件就是要多寫一行
const helmet = Helmet.renderStatic();來避免記憶體洩漏的問題,同時若有使用樣板引擎,meta data 中的動態資料須整合。 - styled-components:是需要按照文件去注入相關資訊。
- isomorphic-fetch:在 Node 端會需要絕對路徑。
- Service Worker:路由衝突 CRA 專案前端可以使用
serviceWorker.unregister();。
Next.js:React SSR 與 CSR 的最佳實踐框架
Next.js 是由 Vercel 平台開發維護的一個 React 框架,已經把大部分 SSR 和 CSR 的問題進行解決。如果有特殊需求,官方也都有很好的範例可供參考。
- 優點:
- 減少多餘的專案設定檔。
- File System based 路由,不需額外安裝套件和設定。
- Code Splitting。
- SSR 支援。
- 缺點:
- 需要參考範例去組合出期待專案架構,對
複製貼上攻城獅來說學習抄襲曲線應該可被接受。 - 思考系統設計跟架構也會需要 Next 風格,不過核心概念還是一樣的。
- 需要參考範例去組合出期待專案架構,對
如果沒有太多奇怪的需求,且是有 React 開發經驗的工程師,開發初期小編覺得可以直接使用 npx create-next-app 開始進行開發。
FAQ:網頁渲染模式常見問題
Q1:現在 Google 爬蟲已經能爬 CSR 網頁了,我還需要 SSR 嗎?
A:需要。 雖然 Google 爬蟲能力提升,但「渲染後爬取」需要消耗更多運算資源,導致爬取頻率降低。此外,除了 Google 外的其他搜尋引擎(或社群平台的 Preview 機器人)對 CSR 的支援並不完美。SSR 能提供最即時、穩定的 SEO 內容。
Q2:SSR 會讓伺服器成本大幅上升嗎?
A:會。 因為伺服器需要額外負擔 CPU 來執行 JavaScript 並產出 HTML 字串。為了平衡成本與效能,建議針對「SEO 關鍵頁面」(如商品、文章)使用 SSR,而「後台管理頁面」或「個人化設定」使用 CSR 即可。
Q3:什麼是 Hydration(注水/水合)?
A:在 SSR 流程中,瀏覽器收到伺服器傳來的靜態 HTML 後,React 會在客戶端再次執行並將事件監聽器掛載到現有的 DOM 上,讓頁面變得具備互動性。這個過程就稱為 Hydration。
喜歡這篇文章,請幫忙拍拍手喔 🤣
