React 18 引入了大量 SSR 效能改進,這些改進大多是在幕後進行的,尤其是針對非框架使用者提供了一些可選選項。其中最有趣的想法是通過伺服器端渲染來提高效能,本文將向您全面介紹。
伺服器端呈現(SSR)是一種能讓 React 應用程式在伺服器上而不是在瀏覽器中呈現的技術。這不僅能提高效能,還能改善使用者體驗。它包括在伺服器上生成 HTML 並將其顯示給客戶端,而 JavaScript 則處理互動。
如果沒有 SSR,就會出現客戶端呈現,即瀏覽器獲取並呈現 HTML。當索引不能正確處理 JavaScript 時,這種策略可能有助於搜尋引擎優化(SEO)。在通過緩慢的網路下載龐大的 JavaScript 包時,這種策略也很有用。
客戶端渲染(CSR)
客戶端渲染(CSR)是指在客戶端(即使用者的網路瀏覽器)渲染網頁。伺服器僅提供原始資料或內容,客戶端 JavaScript 利用這些資料或內容動態構建最終呈現的頁面。
伺服器不傳送完整的 HTML 內容,而是傳送帶有 JS 檔案的最小 HTML。初次載入可能會比較慢,但隨後的載入速度會更快,而且每條路徑都不會出現新的 HTML。
客戶端渲染網站獨立處理邏輯和資料檢索。每個頁面和 URL 都是動態構建的,因此頁面在程式碼執行後即可使用。
當使用者請求頁面時,伺服器會傳送初始 HTML 和所需的 JavaScript 檔案。客戶端在必要時使用 JavaScript 更新頁面,從而避免了全頁面重新載入。
以下是 CSR 流程:
- 使用者在位址列中輸入要訪問的 URL。
- 通過 URL 向伺服器傳送資料請求。
- 伺服器會在第一次請求網站時向客戶端瀏覽器傳送靜態檔案(CSS 和 HTML)。
- HTML 首先載入,然後是 JavaScript。HTML 檔案連線到 JavaScript,顯示開發人員定義的載入符號。使用者看不到網站。
- 下載 JavaScript 後,素材會在客戶端瀏覽器上動態生成。
- 當客戶瀏覽網站並與之互動時,網站內容就會顯現出來。
CSR 的優勢
- 由於採用全頁面重新整理,應用程式的響應速度更快,使用者在頁面導航之間看不到 Flash。
- 向伺服器傳送的 HTTP 請求更少,因為每次頁面載入時都不會再次下載相同的資產。
- 客戶端和伺服器之間有明確的分工;您可以為不同的平臺(如移動、聊天機器人、智慧手錶)快速構建額外的客戶端,而無需修改伺服器程式碼。只要不違反 API 合同,就可以獨立修改客戶端和伺服器上的技術棧。
CSR 的缺點
- 由於需要載入許多頁面所需的框架、應用程式程式碼和資產,因此初始頁面載入時間會增加。
- 在伺服器上,你還必須將其設定為將所有請求路由到一個入口點,並允許客戶端路由從那裡接管。
- 在大多數情況下,需要使用外部庫。
- 在抓取過程中,所有搜尋引擎都會執行 JavaScript,它們可能會檢測到頁面上的空內容。這會在不知不覺中損害應用程式的搜尋引擎優化 (SEO)。
何時應使用客戶端渲染?
- 應用程式的使用者介面非常複雜,頁面和功能眾多。
- 應用程式擁有大量動態資料。
- 網站的首要任務是編寫而不是閱讀。
- 重點是擁有大量使用者的豐富網站。
伺服器端渲染(SSR)
伺服器端渲染(SSR)是指先在伺服器上進行網頁渲染,然後再傳送到客戶端的網路瀏覽器。這種方法不是傳輸原始資料和依賴客戶端,而是由伺服器為網頁生成最終的 HTML 標記併傳送給客戶端。
網路瀏覽器向伺服器傳送資訊請求,檢索使用者特定資料以填充並向客戶端傳送完全渲染的 HTML 頁面。每次使用者訪問網站上的新頁面時,伺服器都會重複整個過程。
下面將詳細介紹 SSR 流程:
- 使用者在位址列中輸入要訪問的 URL。
- 伺服器向瀏覽器傳送準備好渲染的 HTML 響應。
- 瀏覽器顯示頁面(現在可以檢視)並下載 JavaScript。
- 瀏覽器執行 React,使頁面具有互動性。
SSR 的優勢
- 由於需要渲染的程式碼較少,網站首頁的載入速度更快。
- 是簡單和靜態網站的理想選擇。
- 提高搜尋引擎優化,搜尋引擎可以抓取網站。
SSR 的缺點
- 與傳統的客戶端內容呈現方式相比,SSR 需要更多的基礎設施和開發工作。
- SSR 需要為伺服器端呈現和瀏覽器端指令碼編寫單獨的程式碼層,從而增加了程式的複雜性。
- 使用者數量過多會造成瓶頸。
何時應使用伺服器端渲染?
- 應用程式的使用者介面簡單,頁面/功能較少。
- 應用程式中的動態資料較少。
- 網站傾向於讀取而不是寫入。
- 重點不在內容豐富的網站,使用者較少。
客戶端渲染與伺服器端渲染的主要區別
- 效能:客戶端渲染會因 JavaScript 的獲取和執行而減慢初始載入時間。伺服器端渲染可生成完全渲染的 HTML,通常可加快載入速度並帶來更流暢的使用者體驗,尤其是在速度較慢的網路或裝置上。
- 搜尋引擎優化:另一個區別是搜尋引擎優化。客戶端呈現會妨礙搜尋引擎的抓取和索引,因為它依賴於 JavaScript。而伺服器端呈現可使內容隨時可供適當索引。
- 開發設定:客戶端呈現更容易上手,所需的伺服器端程式碼也更少,但隨著應用程式的增長,維護起來可能會變得更具挑戰性。伺服器端呈現需要更多的伺服器端程式碼,實施起來可能更棘手,但它能提供更好的使用者體驗和搜尋引擎優化優勢。
使用 React 18 實現伺服器端渲染
第 1 步:使用 create-react-app
命令列工具建立一個新的 React 應用程式。開啟首選終端,鍵入以下命令。
npx create-react-app server-api-demo-app
第 2 步:切換到新建立的 React 應用程式。
cd server-api-demo-app
第 3 步:要管理路由,在專案中新增 react-router-dom
npm install react-router-dom
第 4 步:在應用程式中包含一些頁面。您可以在 app.js
中包含以下示例路由: (i) Homepage (ii) About
const App = () => ( <div> <Routes> <Route path="/" element={<Home />}></Route> <Route path="/about" element={<About />}></Route> </Routes> </div> );
第 5 步:在兩頁空白處填寫內容。點選 [此處] 以供參考。
第 6 步:在根目錄下新建一個名為 server
的資料夾,然後新增 index.js
和 server.js
檔案。將下面的程式碼複製並貼上到該檔案中。
// server/index.js require("ignore-styles"); require("@babel/register")({ ignore: [/(node_modules)/], presets: ["@babel/preset-env", "@babel/preset-react"], }); require("./server");
該程式碼段配置了用於程式碼翻譯的 Babel,排除了特定檔案(如 “node_modules” 中的檔案),並通過匯入 “server” 模組啟動伺服器。在 React 伺服器端呈現中,該引數通常用於允許伺服器處理和提供 React 元件。
// server/server.js import express from "express"; import React from "react"; import ReactDOMServer from "react-dom/server"; import { StaticRouter } from "react-router-dom/server"; import App from "../src/App"; const app = express(); app.get("/*", (req, res) => { const entryPoint = ["/main.js"]; const { pipe, abort: _abort } = ReactDOMServer.renderToPipeableStream( <StaticRouter location={req.url}> <App /> </StaticRouter>, { bootstrapScripts: entryPoint, onShellReady() { res.statusCode = 200; res.setHeader("Content-type", "text/html"); pipe(res); }, onShellError() { res.statusCode = 500; res.send("<!doctype html><p>Loading...</p>"); }, } ); }); app.listen(3002, () => { console.log("App is running on http://localhost:3002"); });
使用 app.get("/*",...)
,程式碼會為所有路由建立一個路由處理程式。這表明該路由處理程式將處理任何傳入的伺服器請求。在路由處理程式中:
-
main.js
的值被分配給 entryPoint 陣列。這表示用於引導客戶端程式碼的 JavaScript 檔案。 -
ReactDOMServer.renderToPipeableStream()
接收兩個引數:一個用於 HTML 渲染的React Node
和一個包含流引數(可選)的options
物件。它會返回一個包含兩個方法的物件:pipe 和 abort。pipe
方法將 HTML 寫入給定的 Node.js 流。為了允許流式傳輸,我們在onShellReady
中使用 pipe。onAllReady
也可用於靜態生成和爬蟲。 - 當渲染過程結束,HTML 準備好向客戶端傳輸時,就會呼叫
onShellReady()
函式。它將響應狀態程式碼設定為 200,將內容型別頭定義為text/html
,然後使用管道函式將渲染的 HTML 管道到響應中。 - 當渲染過程中出現錯誤時,將執行
onShellError()
回撥函式。它會將響應狀態程式碼設定為500
,併傳送一條 HTML 編碼的簡單錯誤資訊。
第 7 步:在客戶端,我們需要用 index.js
檔案中的 ReeactDOM.hydrareRoot
更新 ReactDOM.createRoot
,以使伺服器生成的 HTML 具有互動性。
// index.js import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; ReactDOM.hydrateRoot( document, <React.StrictMode> <BrowserRouter> <App /> </BrowserRouter> </React.StrictMode> );
第 8 步:要在伺服器上執行程式碼,請在 package.json
檔案中包含以下指令碼。
"ssr": "npm run build && node server/index.js"
該命令將構建專案,在伺服器上執行程式碼,並將結果輸出到 localhost:3002
第 9 步:使用 npm run ssr
命令檢視輸出結果。
React 伺服器元件(RSC)
React 伺服器元件(RSC)將資料抓取和遠端客戶端-伺服器互動納入框架,從而擴充套件了 React 的基礎,使其不僅僅是一個渲染庫。
React 的設計宗旨是模組化和逐步整合到現有程式碼庫中。為了滿足世界對豐富互動性的渴望,它將客戶端和伺服器分離開來,使前端的構建更加靈活。這一點對團隊尤為重要:由不同開發人員建立的兩個 React 元件只有在共享相同基礎的情況下才能一起執行。
為了實現這一目標,React 必須在已有的 Web 標準基礎上進行創新。在過去十年多頁面應用程式(MPA)和單頁面應用程式(SPA)、客戶端和伺服器端呈現之間的演變過程中,我們的目標始終如一:提供快速資料、豐富的互動性,並保持出色的開發人員體驗。
RSC 完全在伺服器上獲取資料並進行渲染,然後將生成的 HTML 流式傳輸到客戶端的 React 元件樹中,並根據需要與其他伺服器和客戶端元件交錯使用。
這種方法避免了客戶端重新渲染的要求,從而提高了效能。由於計算負載由客戶端和伺服器分擔,因此水合可與任何客戶端元件流入的 RSC 同時進行。
小結
有了新的伺服器 API,React 元件現在可以使用 Node.js 或 Web 流渲染成伺服器渲染的 HTML。一些框架(如 Next.js、Remix 和 Gatsby)可以自動完成這一過程,從而提高初始載入時間、搜尋引擎優化、使用者體驗和抵禦 XSS 攻擊的安全性。
SSR 雖然具有優勢,但也會帶來複雜性和伺服器負載的增加,可能不適合聊天或多人遊戲等實時應用。請評估您的需求,確保 SSR 符合您的需要。
評論留言