使用React進行服務器端渲染

什麼是服務器端渲染?如何用React做到這一點?

服務器端渲染, 也被稱為固態繼電器,是JavaScript應用程序在服務器而不是在瀏覽器中呈現的功能。

我們為什麼要這樣做?

  • 它使您的網站擁有更快的首頁加載時間,這是獲得良好用戶體驗的關鍵
  • 這對於SEO至關重要:搜索引擎無法(還?)高效,正確地索引專門呈現客戶端的應用程序。儘管Google對索引編制有了最新的改進,但還有其他搜索引擎,無論如何Google都不是完美的。另外,Google偏愛加載時間短的網站,並且必須加載客戶端不利於提高速度
  • 人們在社交媒體上共享您的網站頁面時非常好,因為他們可以輕鬆收集很好地共享鏈接所需的元數據(圖像,標題,描述..)

如果沒有服務器端渲染,您的所有服務器都將是一個沒有正文的HTML頁面,只有一些腳本標記,然後瀏覽器就會使用這些腳本標記來呈現應用程序。

客戶端渲染的應用程序非常適合在首頁加載後進行的任何後續用戶交互。服務器端渲染使我們可以在客戶端渲染的應用程序和後端渲染的應用程序的中間位置獲得優勢:頁面是在服務器端生成的,但是與頁面加載後的所有交互都是在客戶端處理的。

但是,服務器端渲染也有其缺點:

  • 可以說,簡單的SSR概念證明很簡單,但是SSR的複雜性會隨著應用程序的複雜性而增加
  • 在服務器端渲染大型應用程序可能會佔用大量資源,並且在繁重的負載下,與客戶端渲染相比,它甚至可能提供較慢的體驗,因為您只有一個瓶頸

服務器端渲染React應用所需的一個非常簡單的示例

SSR設置可能會變得非常非常非常複雜,並且大多數教程都會介紹Redux反應路由器以及從一開始的許多其他概念。

為了了解SSR的工作原理,讓我們從基礎知識開始實施概念驗證。

如果您只想研究提供SSR的庫,而不必打擾基礎工作,請跳過本段

為了實現基本的SSR,我們將使用Express。

如果您不熟悉Express,或者需要一些幫助,請在這裡查看我的免費Express Handbook:https://flaviocopes.com/page/ebooks/

警告:SSR的複雜性會隨著應用程序的複雜性而增加。這是渲染基本React應用程序的最低要求。對於更複雜的需求,您可能需要做更多的工作,或者還檢查React的SSR庫。

我假設你用以下方法啟動了一個React應用create-react-app。如果您只是嘗試,請立即使用安裝npx create-react-app ssr

使用終端轉到主應用程序文件夾,然後運行:

npm install express

您的應用程序目錄中有一組文件夾。創建一個名為的新文件夾server,然後進入它並創建一個名為server.js

create-react-app約定,該應用程序位於src/App.js文件。我們將加載該組件,並使用ReactDOMServer.renderToString(),由提供react-dom

您得到的內容./build/index.html文件,然後替換<div id="root"></div>佔位符,它是應用程序默認掛接的標籤,帶有`<div id="root">\${ReactDOMServer.renderToString(<App />)}</div>

裡面的所有內容buildExpress將按原樣提供該文件夾。

import path from 'path'
import fs from 'fs'

import express from ‘express’ import React from ‘react’ import ReactDOMServer from ‘react-dom/server’

import App from ‘…/src/App’

const PORT = 8080 const app = express()

const router = express.Router()

const serverRenderer = (req, res, next) => { fs.readFile(path.resolve(’./build/index.html’), ‘utf8’, (err, data) => { if (err) { console.error(err) return res.status(500).send(‘An error occurred’) } return res.send( data.replace( ‘<div id=“root”></div>’, &lt;div id="root"&gt;</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">ReactDOMServer</span>.<span style="color:#a6e22e">renderToString</span>(<span style="color:#f92672">&lt;</span><span style="color:#a6e22e">App</span> <span style="color:#f92672">/&gt;</span>)<span style="color:#e6db74">}</span><span style="color:#e6db74">&lt;/div&gt; ) ) }) } router.use(’^/$’, serverRenderer)

router.use( express.static(path.resolve(__dirname, ‘…’, ‘build’), { maxAge: ‘30d’ }) )

// tell the app to use the above rules app.use(router)

// app.use(express.static(’./build’)) app.listen(PORT, () => { console.log(SSR running on port </span><span style="color:#e6db74">${</span><span style="color:#a6e22e">PORT</span><span style="color:#e6db74">}</span><span style="color:#e6db74">) })

現在,在客戶端應用程序中src/index.js,而不是致電ReactDOM.render()

ReactDOM.render(<App />, document.getElementById('root'))

稱呼ReactDOM.hydrate()相同,但是一旦React加載,它還具有將事件偵聽器附加到現有標記的附加功能:

ReactDOM.hydrate(<App />, document.getElementById('root'))

所有的Node.js代碼都需要由巴別塔,因為服務器端Node.js代碼不了解JSX,也不了解ES模塊(我們用於include聲明)。

安裝以下4個軟件包:

npm install @babel/register @babel/preset-env @babel/preset-react ignore-styles

ignore-styles是Babel實用程序,它將告訴它忽略使用import句法。

讓我們在中創建一個入口點server/index.js

require('ignore-styles')

require(’@babel/register’)({ ignore: [/(node_modules)/], presets: [’@babel/preset-env’, ‘@babel/preset-react’] })

require(’./server’)

編譯React應用程序,以填充build /文件夾:

npm run build

讓我們運行這個:

node server/index.js

我說這是一種簡單的方法,它是:

  • 使用導入時,它無法正確處理渲染圖像,而導入需要Webpack才能正常工作(這使整個過程變得非常複雜)
  • 它不處理頁面標頭元數據,這對於SEO和社交共享目的非常重要(除其他事項外)

因此,雖然這是使用的一個很好的例子ReactDOMServer.renderToString()ReactDOM.hydrate要獲得此基本的服務器端渲染,僅用於實際用途還不夠。

使用庫的服務器端渲染

SSR很難做到正確,而且React沒有實際的方法來實現它。

如果值得付出麻煩,複雜化和開銷來獲得好處,而不是使用其他技術來提供這些頁面,那還是值得商de的。關於Reddit的討論在這方面有很多意見。

當服務器端渲染很重要時,我的建議是依賴從一開始就牢記此目標的預製庫和工具。

我特別建議Next.js蓋茨比

免費下載我的反應手冊


更多反應教程: