前後端分離或是在一起間接影響網頁渲染的方式,常見的渲染形式會有用戶端渲染 (CSR) 和伺服器端渲染 (SSR) 兩種。
這就好像男女朋友是否同居一樣,會大大影響兩人的日常生活型態,分開時兩者的自由度都較高,在一起同居時總會需要考慮彼此狀態。
前後端要分離或是在一起? 渲染的方式該怎麼決定? 小編覺得也各自有各自的優缺點,接下來就來開箱 CSR 跟 SSR 吧。
隨著瀏覽器的效能變好,帶有顯示邏輯的渲染可以轉移到瀏覽器端,於是也就出現單頁應用程式 Single Page Application (SPA) 與 Client Side Render (CSR) 的概念。
Single Page Application (SPA) 不同以往產生完整 HTML 的做法,會將網頁都打包 (bundle) 後才在用戶端執行,其中 bundle 可以想像成是 APP 的安裝與執行檔。
在 SPA 中畫面中元素不再直接產生在頁面中,初始時需要 CSR 的部分會是空白的,改由透過 API 要回來的資料和 bundle 檔在前端動態產生渲染畫面。
舉個簡單的例子來說,登入之後不需要跳轉至新的頁面並重新載入,只需要透過要回來的資料來更改網頁中的元素或元件即可。
HTML 由 Server 端產生,所以用戶看到的就是最終版 HTML,會有三種預渲染形式
註: Pre Render 這類外掛適用於 CRA 專案但可能會跟不上 React 新功能所產生的問題
由於網頁需等待 Bundle 完整載入後才會渲染,速度較慢即使透過 Code Splitting 去把程式碼和用到的函式庫分離開來,但仍然沒有 SSR 產生來的快速。
目前非所有搜尋引擎都能爬取 SPA 中的內容,所以理想狀況是第一頁在伺服器先進行靜態生成或伺服器端端渲染
伺服器端較簡易的實作方式是用 Node.js 語法來撰寫,理論上前端用到的套件幾乎在後端都會再用到,在實作伺服器渲染時可能會遇到的問題:
渲染時 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
。
套件們使用時需要注意的事項:
const helmet = Helmet.renderStatic();
來避免記憶體洩漏的問題,同時若有使用樣版引擎,meta data 中的動態資料須整合serviceWorker.unregister();
Next.js 是由 Vercel 平台開發維護的一個 React Framework,已經把大部分 SSR 問題進行解決,如果有特殊需求官方也都有很好的範例。
如果沒有太多奇怪的需求,且是有 React 開發經驗的工程師,開發初期小編覺得可以直接使用 npx create-next-app
開始進行開發。