使用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盖茨比

免费下载我的反应手册


更多反应教程: