如何为 React 应用程序启用服务器端渲染

<$>[warning] **警告:**本教程旨在简要介绍ReactDOM.hydrate()ReactDOMServer.rendertoString()

或者, Next.js提供了创建与 React 构建的静态和服务器渲染应用程序的现代方法。

介绍

服务器侧渲染(SSR)是一种流行的技术,用于在服务器上渲染客户端侧单页应用程序(SPA),然后向客户端发送完全渲染的页面。

这种方法可能对搜索引擎优化(SEO)有用,当索引不正确处理JavaScript时,它也可以在下载大型JavaScript套件时有益。

在本教程中,您将使用 Create React App初始化 React 应用程序,然后修改该项目以启用服务器侧渲染。

在本教程结束时,您将有一个与客户端React应用程序和服务器侧Express应用程序的工作项目。

前提条件

要完成本教程,您将需要:

本教程是用 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' 脚本

要使服务器代码正常工作,您需要使用 webpackBabel来组合和转载。

<$>[注] **注:**本教程的早期版本安装了babel-core,babel-preset-envbabel-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

然后,添加envreact-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: nodeexternals: [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-serverdev: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 主题页面以获取练习和编程项目。

Published At
Categories with 技术
Tagged with
comments powered by Disqus