<$>[warning]
**警告:**本教程旨在简要介绍ReactDOM.hydrate()
和ReactDOMServer.rendertoString()
。
或者, Next.js提供了创建与 React 构建的静态和服务器渲染应用程序的现代方法。
介绍
服务器侧渲染(SSR)是一种流行的技术,用于在服务器上渲染客户端侧单页应用程序(SPA),然后向客户端发送完全渲染的页面。
这种方法可能对搜索引擎优化(SEO)有用,当索引不正确处理JavaScript时,它也可以在下载大型JavaScript套件时有益。
在本教程中,您将使用 Create React App初始化 React 应用程序,然后修改该项目以启用服务器侧渲染。
在本教程结束时,您将有一个与客户端React应用程序和服务器侧Express应用程序的工作项目。
前提条件
要完成本教程,您将需要:
- Node.js 是本地安装的,您可以按照 如何安装 Node.js 和创建本地开发环境进行操作。
本教程是用 Node v16.13.1, npm
v8.1.2, react
v17.0.2, @babel/core
v7.16.0, webpack
v4.44.2, express
v4.17.1, nodemon
v2.0.15 和 npm-run-all
v4.1.5 验证的。
步骤 1 — 创建 React 应用程序并修改应用程序组件
首先,使用 npx启动新的 React 应用程序,使用创建 React 应用程序的最新版本。
让我们打电话给应用程序, react-ssr-example:
1npx create-react-app react-ssr-example
然后,将CD
放入新目录:
1cd react-ssr-example
最后,启动新客户端应用程序以验证安装:
1npm start
您将看到一个示例 React 应用程序显示在您的浏览器窗口中。
现在,在src
目录中,让我们创建一个新的<Home>
组件:
1nano src/Home.js
接下来,将以下代码添加到Home.js
文件中:
1[label src/Home.js]
2function Home(props) {
3 return <h1>Hello {props.name}!</h1>;
4};
5
6export default Home;
这将创建一个<h1>
标题,并向一个名字发送一个Hello
消息。
接下来,让我们在应用程序
组件中渲染<Home>
,在src
目录中打开App.js
文件:
1nano src/App.js
然后,用这些新的代码代码代替现有代码行:
1[label src/App.js]
2import Home from './Home';
3
4function App() {
5 return <Home name="Sammy"/>;
6}
7
8export default App;
这将沿名称
传递到主页
组件,因此您预计会显示的消息是:
1[secondary_label Output]
2"Hello Sammy!"
在应用程序的 index.js 文件中,您将使用 ReactDOM 的 ‘hydrate’ 方法而不是 render
来向 DOM 渲染器表示,您打算在服务器侧渲染后重新氢化应用程序。
让我们在src
目录中打开index.js
文件:
1nano src/index.js
然后,用以下代码取代index.js
文件的内容:
1[label src/index.js]
2import React from 'react';
3import ReactDOM from 'react-dom';
4
5import App from './App';
6
7ReactDOM.hydrate(
8 <React.StrictMode>
9 <App />
10 </React.StrictMode>,
11 document.getElementById('root')
12);
这结束了设置客户端,您可以继续设置服务器端。
步骤 2 — 创建快递服务器并渲染应用程序组件
现在你已经有了应用程序,让我们设置一个服务器,它将发送与渲染版本. 您将使用 Express for the server。
<$>[注]
注: Create React App的react-scripts
将安装一个版本的express
作为webpack-dev-server
的要求。
接下来,在项目的根目录中创建一个新的服务器
目录:
1mkdir server
然后,在服务器
目录中,创建一个新的index.js
文件,其中包含 Express 服务器代码:
1nano server/index.js
添加需要的导入并定义一些常数:
1[label server/index.js]
2import path from 'path';
3import fs from 'fs';
4
5import React from 'react';
6import ReactDOMServer from 'react-dom/server';
7import express from 'express';
8
9import App from '../src/App';
10
11const PORT = process.env.PORT || 3006;
12const app = express();
接下来,添加一些错误处理的服务器代码:
1[label server/index.js]
2// ...
3
4app.get('/', (req, res) => {
5 const app = ReactDOMServer.renderToString(<App />);
6 const indexFile = path.resolve('./build/index.html');
7
8 fs.readFile(indexFile, 'utf8', (err, data) => {
9 if (err) {
10 console.error('Something went wrong:', err);
11 return res.status(500).send('Oops, better luck next time!');
12 }
13
14 return res.send(
15 data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
16 );
17 });
18});
19
20app.use(express.static('./build'));
21
22app.listen(PORT, () => {
23 console.log(`Server is listening on port ${PORT}`);
24});
可以从客户端应用程序直接从服务器导入<App>
组件。
这里发生了三件重要的事情:
- Express 被用来将
构建
目录中的内容作为静态文件 - ReactDOMServer 的
renderToString
被用来将应用程序转换为静态 HTML 字符串 *从构建的客户端应用程序中读取静态index.html
文件。
步骤 3 — 配置 webpack、Babel 和 'npm' 脚本
要使服务器代码正常工作,您需要使用 webpack和 Babel来组合和转载。
<$>[注]
**注:**本教程的早期版本安装了babel-core
,babel-preset-env
和babel-preset-react-app
。
Create React App 的「react-scripts」可安裝下列套件:「webpack」,「webpack-cli」,「webpack-node-externals」,「@babel/core」,「babel-loader」,「@babel/preset-env」,「@babel/preset-react」。
接下来,在项目的 root 目录中创建一个新的 Babel 配置文件:
1nano .babelrc.json
然后,添加env
和react-app
预设:
1[label .babelrc.json]
2{
3 "presets": [
4 "@babel/preset-env",
5 "@babel/preset-react"
6 ]
7}
<$>[注]
**注:**本教程的早期版本使用了 .babelrc
文件(没有 .json
文件扩展)。
现在,为使用 Babel Loader 传输代码的服务器创建 Webpack 配置,开始在项目根目录中创建 webpack.server.js
文件:
1nano webpack.server.js
然后,将以下配置添加到webpack.server.js
文件中:
1[label webpack.server.js]
2const path = require('path');
3const nodeExternals = require('webpack-node-externals');
4
5module.exports = {
6 entry: './server/index.js',
7 target: 'node',
8 externals: [nodeExternals()],
9 output: {
10 path: path.resolve('server-build'),
11 filename: 'index.js'
12 },
13 module: {
14 rules: [
15 {
16 test: /\.js$/,
17 use: 'babel-loader'
18 }
19 ]
20 }
21};
通过此配置,转载的服务器包将输出到名为index.js的文件夹中的服务器构建
文件夹。
注意从webpack-node-externals
中使用target: node
和externals: [nodeExternals()]
,这将忽略包中的node_modules
中的文件;服务器可以直接访问这些文件。
这完成了依赖安装和 webpack 和 Babel 配置。
现在,重新访问package.json
并添加npm
助手脚本:
1nano package.json
将dev:build-server、dev:start 和dev 脚本添加到package.json 文件中,以构建和服务 SSR 应用程序:
1[label package.json]
2"scripts": {
3 "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
4 "dev:start": "nodemon ./server-build/index.js",
5 "dev": "npm-run-all --parallel build dev:*",
6 // ...
7},
dev:build-server
脚本将环境设置为development
,并呼吁与您之前创建的配置文件一起使用webpack
。
dev
脚本呼吁npm-run-all
在平行
中运行build
脚本和所有以dev:*
开始的脚本 - 包括dev:build-server
和dev:start
。
<$>[注]
**注:**您不需要在「package.json」
文件中修改现有的开始
、构建
、测试
和排除
脚本。
npm-run-all
用于同时运行多个命令。
现在让我们通过在您的终端窗口中输入以下命令来安装这些包:
1npm install [email protected] --save-dev
2npm install [email protected] --save-dev
有了这个,您可以运行以下操作来构建客户端应用程序,包装和传输服务器代码,并在:3006
上启动服务器:
1npm run dev
服务器 webpack config 现在将监控更改,服务器将重新启动更改,但对于客户端应用程序,每次进行更改时都需要手动重建。
<$>[注] 注: 有一个 打开这个问题在这里。
现在,在您的 Web 浏览器中打开 http://localhost:3006/
,并观察您的服务器侧渲染应用程序。
此前,查看源代码揭示:
1[secondary_label Output]
2<div id="root"></div>
但是现在,随着您所做的更改,源代码显示:
1[secondary_label Output]
2<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>
服务器侧渲染成功地将<App>
组件转换为HTML。
结论
在本教程中,您初始化了 React 应用程序并启用了服务器侧渲染。
事情往往变得更复杂,一旦路由,数据采集或Redux也需要成为服务器侧渲染应用的一部分。
使用SSR的一个主要好处是有一个可以搜索其内容的应用程序,即使对于不执行JavaScript代码的扫描程序,这可以帮助搜索引擎优化(SEO)和向社交媒体渠道提供元数据。
SSR 也经常可以帮助性能,因为一个完全加载的应用程序在第一个请求时被从服务器发送下来。对于非微观的应用程序,您的里程可能有所不同,因为 SSR 需要一个设置,这可能会变得有点复杂,并对服务器产生更大的负载。
如果您想了解更多关于 React 的信息,请查看我们的 如何在 React.js 中编码系列,或查看 我们的 React 主题页面以获取练习和编程项目。