前端渲染模式的選擇

2026年7月23日

💎 加入 E+ 會員方案 與超過千位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

在現代前端開發中,渲染模式的選擇,幾乎是每個新專案最開始必須要面對問題。因此,前端工程師需要知道有哪些不同的渲染模式、以及需要知道在什麼情境該用哪一種渲染模式。在本期的前端主題文中,我們將會介紹常見的渲染模式,以及不同模式的適用場景。

在往下閱讀前,推薦先讀過 E+ 前端主題文中的 關鍵渲染路徑 (critical rendering path) 這篇主題文,因為本期主題文有許多先備知識,不會在這邊展開細節,因此先讀完那兩篇再來讀這篇,會比較能有效吸收。

客戶端渲染 client-side rendering (CSR)

從網頁歷史來看,在早期前後端沒有特別分離的狀況下,都是由後端渲染,然後由後端輸出到前端後,前端再搭配 JavaScript 負責一些簡單互動與動畫。不過,隨著瀏覽器越來越強大,變得有能力在瀏覽器上做複雜運算與渲染;與此同時,在客戶端渲染能帶來更佳的使用者體驗,也讓業界開始發展客戶端渲染 (client-side rendering,接下來簡稱 CSR)。

在 CSR 模式下的渲染流程 在 CSR 模式下,請求發送後,會先拿到一個空白的 HTML,做為最基本的骨架

<html>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>

接著會根據 <script> 標籤來開始下載 JavaScript (上面的例子會是下載 bundle.js),然後用 JavaScript 來去渲染,包含由 JavaScript 來產出 DOM,並完成 關鍵渲染路徑 (critical rendering path) 一文談到的渲染流程。渲染後,才會根據客戶端寫的程式碼,呼叫後端 API 來拉取資料,拉完資料呈現完主要內容,才會上報 Web Vitals 的 LCP。

CSR 的優點 CSR 之所以會出現,是因為上面提到這種傳統的「由後端把東西都準備好後送到前端」渲染模式,因為會有整個頁面換頁的狀況,會導致使用者體驗不那麼理想。不過,在 CSR 的模式下,每當有任何與後端的互動 (例如點擊按鈕送出表單),不需用由伺服器端送新的一頁,所以不會有因為換頁造成的不佳使用者體驗。

除此之外,CSR 把前後端的程式碼切的很清楚,不像傳統會把程式碼都寫在一起;在可維護性上,CSR 因相對好維護。

CSR 的問題 雖然 CSR 可以帶給使用者更好的使用體驗,但也有很顯而易見的問題:

  • 剛進網站的等待時間比較久:CSR 模式下,使用者進到網站後,一開始會是全白或骨架 (skeleton) 的畫面,必須等到 JavaScript 下載完、解析完、執行完、更新完 DOM,才會有網站真正的畫面。當 CSR 的建構時的打包產物 (bundle) 越大包,要花越多時間下載與解析,也會等越久。這段等待時間的使用者體驗不是那麼好。
  • SEO 比較沒那麼好:由於 CSR 模式下,一開始伺服器端只會送給客戶端一個空白 HTML,搜尋引擎的爬蟲也只會爬到空白的 HTML,所以在爬蟲方面爬的結果通常是空白的。即使現在許多搜尋引擎會在爬蟲時執行 JavaScript,但不保證該搜尋引擎的 JavaScript 執行方式如預期,所以無法保證 SEO 是否良好。

如何解決 CSR 的問題

  • 解決剛進網站要等比較久的問題:
    • 盡可能減少打包產物的大小 (reduce bundle size),一般業界的標準是在 gzipped 壓縮後在 100 KB 以內。常見的作法是透過程式碼分割 (code splitting) 搭配懶加載 (lazy loading),不要一次下載整包 JavaScript,而是只下載當前所需的 JavaScript 即可。
    • 透過預載 (preload),盡可能提早把所需的資源都先下載下來,這樣就可以減少等待的時間。
    • 透過 Service Worker 層的快取 (cache),把 HTML、CSS、JavaScript 放到 Service Worker,只要快取還沒有過期,下次使用者再訪問同一個頁面時,就可以免去前面的下載時間。
  • 解決 SEO 相關問題:先前 Vercel 的研究發現,Google 的搜尋引擎基本上是會下載與執行 JavaScript 的,所以以 Google 搜尋來說,CSR 的 SEO 問題沒那麼大。但是仍推薦盡可能把 JavaScript 減到最小,這是因為搜尋引擎會為網站分配爬蟲的成本 (crawl budget),所以如果 JavaScript 太大包,花太多成本執行,可能就會導致成本花完後,有些頁面沒被執行 JavaScript,導致 SEO 不好。

關於 CSR 的相關討論,Client-side Rendering 這個開源專案 (連結),有做非常詳細的分析,推薦有時間的人,可以好好一讀。

伺服器端渲染 Server-side rendering

在談完 CSR 後,接著讓我們來談 SSR,也就是伺服器端渲染 (Server-side rendering)。由於 SSR 的具體實作細節,在過去有不小的變化,在這邊我們會拆成不同的 SSR 來討論。

傳統的 SSR

如上面提到,在早些年基本上沒有什麼前後端分離、沒有 CSR 的存在,網頁應用基本上都是在伺服器端完成所有處理,包含像資料庫拿資料、把頁面渲染好,然後傳給客戶端。

傳統 SSR 的好處:比起 CSR,傳統的 SSR 不用把整包的 JavaScript 傳到客戶端,而是把渲染好的 HTML 傳給前端,這樣的好處是,如果客戶端是用非高階裝置、非高速網路,也不用擔心 JavaScript 太大一包要下載與解析很久。與此同時,因為是直接送給前端渲染好的 HTML,是有內容的,所以 SEO 的問題也不用擔心。

傳統 SSR 的問題:雖然傳統 SSR 有其好處,但 CSR 會出現也不是沒道理的,當時之所以 CSR 會盛行,是因為傳統的 SSR 每次有操作時 (例如送出表單後) 整個頁面要重新加載,導致有換頁的體驗,這樣的使用者體驗不是太好。

SSR + 注水 (hydration)

這時你可能會問,有沒有什麼方法,是可以有傳統 SSR 先渲染好 HTML 的優點,又同時可以像 CSR 這樣後續操作都由客戶端接手,可以提供比較好的使用體驗? 事實上近代開發者用的 SSR 正是用這樣的方式。

如果用 Next.js 這種框架的 SSR,會是有別於傳統的 SSR,這種作法一樣是先把 HTML 在伺服器端渲染好;不過不同的地方在於,傳到前端後,會有一個注水 (hydration),然後讓後續的操作變得不需用換頁,帶來更好的使用體驗。

具體來說,流程會是這樣進行:

  • 在伺服器完成渲染後,將完整的 HTML 傳到客戶端,這時客戶端已經有完整的網頁內容可以看到。
  • 然後客戶端下載少量的 JavaScript,在客戶端做事件綁定 (就是上面提到的注水 hydration),因為初始畫面已經有了,注水只需用依照已經有的 DOM 來綁定事件處理器即可。
  • 注水完成後,就會跟 CSR 一樣,由客戶端接管,使用者會有良好的互動體驗,而不會像傳統的 SSR 這樣需要整個換頁。

SSR + 注水 的好處:解決了傳統 SSR 的互動性問題,同時解決了 CSR 在前面有一大段空白的問題。

SSR + 注水 的問題:雖然這方式看似解決前兩種方式的問題,但仍有自己的問題。具體來說,雖然在 HTML 送達客戶端後就立即能展示畫面,不會有空白的那一段;但在有 HTML 到完成 JavaScript 注水這段期間,會是看得到畫面,但沒辦法有互動。相信讀者們過去或多或少遇過,網站有畫面,但怎麼點按鈕都沒用,這種不好的使用體驗,是 SSR + 注水的主要問題。

串流式的 SSR

針對 SSR + 注水會有的問題,業界近年來也提出了更好的解決方案。其中的第一個是透過串流 (streaming) 的方式來做 SSR。

在業界剛有 SSR + 注水時,基本上都是伺服器端渲染好完整的 HTML,然後一次傳給前端。但因為 HTML 是可以被串流的方式傳送的,所以把串流搭配 SSR,有某個部分完成,就直接渲染,然後直接傳完成的部分。

這樣一來,可以不用等所有資料都拿到後才一次渲染,也不用等所有都在伺服器端渲染完成後,才傳給客戶端,對使用者來說,體感上的使用體驗會比較好。

改良版的注水

不僅是 SSR 本身可以透過串流的方式優化,注水也是可以優化的面向;具體來說,當 SSR 搭配注水的方式被提出時,最早的作法都是一次把整個頁面注水,所以要整個頁面都完成注水後,才可以互動,而目前業界也有幾種不同的注水優化方式。

漸進式注水 (Progressive Hydration) 漸進式注水,可以設定哪個部分先注水,在頁面剛加載時只注水重要的部分,其他部分等後續再注水。先注水的部分完成注水後,就可以有互動性,不用等到整個頁面都被注水才可以互動。

島嶼架構 (Island Architecture) 島嶼架構 (island architecture) 是由 Etsy 的架構師 Katie Sylor-Miller  提出的。該架構把頁面拆成不同元件 (就像島嶼一樣),而只有需要互動的部分才注水。比起漸進式注水,可以把島嶼架構理解成拆分式注水 (separately hydrated)。

某一塊的注水不影響另外一塊,所以假如有某一塊元件要花比較久的時間處理,其他塊還是可以先完成注水 (漸進式的話,如果先注水的花比較久,後面注水的就會先被卡住)。

選擇式注水 (Selective Hydration) 選擇式注水是由 React 團隊提出的,這個做法也是會拆分成不同的元件,預設會依照 React 虛擬 DOM 樹上出現的順序,逐一為元件注水;與此同時,如果使用者跟某一個元件互動時,React 會停下其他元件的注水,優先注水使用者在互動的元件。這樣做的好處在於,使用者先互動的部分,優先被注水就可以先互動,體驗會好一點。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們