React Server Side Render 簡介 伺服器渲染觀念與常見問題

me
林彥成
2017-08-31 | 3 min.
文章目錄
  1. 1. Client Side Render (CSR) 簡介
    1. 1.1. Single Page Application (SPA)
    2. 1.2. Client Side Render (CSR)
  2. 2. Server Side Render (SSR) 簡介
  3. 3. Server Side Render 常見問題
    1. 3.1. Next.js

淺談像是 React 的 SPA (Single Page Application) 前端專案如何實作 Server Side Render,伺服器渲染有哪些好處,又會遇到哪些問題?

Client Side Render (CSR) 簡介

隨著瀏覽器的效能開始越來越好,帶有顯示邏輯的渲染可以轉移到瀏覽器端,於是也就慢慢出現了單頁應用程式 Single Page Application (SPA) 與 Client Side Render (CSR) 的概念。

Single Page Application (SPA)

不同以往在伺服器實作不同頁面的做法,現在會將網頁都打包 (bundle),這裡可以先把 bundle 想像成是 APP 的 apk 檔。

Client Side Render (CSR)

在 SPA 中畫面中的元素不再透過直接產生在頁面中而是前端動態產生,SPA 透過 API 要回來的資料搭配顯示邏輯來渲染畫面。

舉個簡單的例子來說,登入之後不需要跳轉至新的頁面並重新載入,只需要透過要回來的資料來更改網頁中的元素(元件)即可。

Server Side Render (SSR) 簡介

什麼是 Server Side Render (伺服器渲染)? 為什麼 SPA 還會需要實作伺服器端渲染呢?

  1. 網頁需等待 Bundle 完整載入後才會渲染
  2. 非所有搜尋引擎都能爬取 SPA 中的內容

雖然透過 webpack code splitting 單元中介紹的,去把自己的程式碼和用到的函式庫分離開來,但仍然沒有傳統後端直接產生來的快速。

常見的解決方法

  1. Static Generation (SG): 透過 Pre-rendering 工具預先 render 頁面產生靜態檔
  2. Server-side Rendering: 每次 Request 都即時將資料存在狀態中並 render 後回傳
  3. Incremental Static Regeneration (ISR): 定期重新進行 SG 避免頁面沒有抓到較新資訊的問題

理想狀況是第一頁在伺服器先進行 SSR,前端就不需等待向後端取得資料的時間 (ex 熱門購物清單),SPA 在操作上也不會有整個頁面重新刷新的問題,這樣兩種的優點都能夠兼得。

Server Side Render 常見問題

在實作伺服器渲染時可能會遇到的問題:

  1. 由於 SPA 是由狀態來決定元件的顯示,那伺服器端的狀態該如何決定呢?
  2. 後端渲染出來的會不會和前端渲染出來的有差異? RWD?
  3. 如果有使用狀態管理的函式庫像是 Redux 需要特別處理嗎?
  4. 前端 SPA 用的路由會影響嗎?

渲染時 react 會幫我們確認 markup 的 checksum 是否相同,若不同就會在 client 端重新渲染一次。

後端在做 redux 的 SSR 時,可以利用初始或運算後的狀態去渲染頁面,但之後需要將這個狀態也傳回前端,前端接收到之後再重新產生 store 傳入 APP 中。

另外前端如果有用到像是 window.innerWidth 這種操作去做條件渲染時就一定會有問題,不正確的狀態或是沒考慮過的操作都會 markup 的 checksum 有錯誤,要特別謹記。

若有用到 router 的部分不管是前後端都要使用 match 來避免前後端不一致。

  • ReactRouter: 要利用 match 然後使用 RouterContext,還有一些情境可能會用到 StaticRouter
  • Redux: 初始狀態加上從後端計算後的資料做一個 Store,接著在 renderToString 時把元件轉成 html 的字串,並先前狀態整合進去
  • React-Helmet: 按照文件就是要多寫一行const helmet = Helmet.renderStatic();來避免記憶體洩漏的問題,同時若有使用樣版引擎,meta data 中的動態資料須整合
  • style-component: 是需要按照文件去注入相關資訊
  • innerWidth or navigator 等瀏覽器才有的物件: 因為 Server 沒有這些東西,必須等到元件 mount 後,意味著不可以利用這些物件來做條件渲染
  • isomorphic-fetch: 在 node 端會需要絕對路徑
  • serviceWorker: 前端路由與後端路由衝突,CRA 專案前端可以使用 serviceWorker.unregister();
  • Server-side bundle: 較簡易的實作方式是用 Node.js 語法來撰寫 Server 端,從以上情況看來,前端用到的套件幾乎在後端都會再用到。那如果要減少 Server-side bundle 大小來爭取執行速度時,也就是 nodemodule 不一起 build 進來的情況下,webpack 的 external 設定要設一下。上傳到伺服器時,會需要重新 npm install 因為有用到,其他要注意的大概是 webpack target: nodelibraryTarget: commonjs2

解決方案上

  • 建議使用 Next.js,大部分問題有幫我們解決掉,人力不足時,推薦使用。
  • prerender-spa-plugin 這類外掛用於使用 Create Script 時的方案,但很可能會跟不上 React 的升級速度而產生問題,像是 lazy load 的部分。

Next.js

Next.js 是由 Vercel 平台開發維護的一個 React Framework,已經把大部分的問題進行解決,如果有特殊需求官方也都有很好的範例

優點

  • 減少多餘的專案設定檔
  • File System based 路由,不需額外安裝套件和設定
  • Code Splitting
  • SSR 支援

缺點

  • 需要參考範例去組合出期待專案架構,對複製貼上攻城獅來說學習抄襲曲線應該可被接受
  • 思考系統設計跟架構也會需要 Next 風格,不過核心概念還是一樣的。

如果沒有太多奇怪的需求,且是有 React 開發經驗的工程師,開發初期小編覺得可以直接使用 npx create-next-app 開始進行開發。


喜歡這篇文章,請幫忙拍拍手喔 🤣

share