前瞻
为了方便理解服务端渲染的原理,开始从零搭建一套简易的 React SSR。
需要用到的技术栈:
- React 全家桶,基于最新的 React18.2.0 版本
- Node Express 框架
此次,并没有集成 TypeScript,是因为 TypeScript 的作用与 SSR 原理并没有啥关系。
从零开始搭建
Node Server 搭建
需要安装的依赖项:
- npm i express(后端服务,这里以 express 为例子)
- npm i -D nodemon(启动 Node 程序时监听文件的变化,变化即刷新)
- npm i -D webpack webpack-cli webpack-node-externals(webpack-node-externals:排除掉 node_modules 中所有的模块,该库只针对于 node 环境,web 环境是不需要的)
express 服务:
webpack 配置(你可以将该文件命名为 server.config.js,方便之后引入客户端配置好区分):
文件树:
React 搭建
需要安装的依赖项:
- npm i react react-dom
- npm i -D webpack-merge
- npm i -D babel-loader @babel/preset-react @babel/preset-env
App 组件:
express 服务更新为:
ReactDOMServer 对象允许你将组件渲染成静态标记,通常,它被使用在 Node 服务端上
webpack 配置更新为:
如果在以上步骤中出现以下报错:
- const AppHtmlString = ReactDOMServer.renderToString();
^
SyntaxError: Unexpected token ’<‘
- Error: Cannot find module ‘@babel/core’
- babel-loader@9 requires Babel 7.12+ (the package ‘@babel/core’). If you’d like to use Babel 6.x (‘babel-core’), you should install ‘babel-loader@7’.
- 原因是因为缺少了@babel/core 这个包,导致解析不了 jsx 语法
- 解法办法:npm install @babel/core —save
文件树:
效果:
至此,服务端渲染已完成,但此时页面并不具备交互性,因为渲染成的页面是个静态页面,还需要进行 hydration 水合!
Hydration 搭建
此步骤将使静态页面具备交互性,从而实现完整的 SSR。
创建客户端,并进行 Hydration
express 服务更新为:
创建属于客户端的 webpack 配置:
文件树:
效果:
访问部署好的静态资源
之后,再引入打包好的 App 实例,express 服务更新为:
值得注意的是:上方 body 中的 root 部分不能有空格(即换行),否则会报错
效果:
至此,Hydration 的工作就完成了,此时页面具有了交互性。
Router 搭建
需要安装的依赖项:
- npm i react-router-dom —save(默认会自动安装 react-router)
注意:路由在客户端及服务端都要配置!
使用 webpack-merge 进行合并配置,config 更新为:
路由配置文件:
客户端路由配置:
服务端路由配置:
App 路由配置:
文件树:
效果:
至此,Router 搭建完成。
Redux 搭建
需要的依赖项:
- npm i react-redux @reduxjs/toolkit
创建 store 以及 home 切片
客户端配置 store:
服务端配置 store:
页面展示数据:
文件树:
效果:
关于异步 action,即 createAsyncThunk API 的使用和原来在 React 项目中是一样的,这里就没有演示了。
至此,Redux 的搭建已完成,并且已经成功搭建了一个简易的 React SSR 了。
总结
在 React 中创建 SSR 应用时,需要调用 ReactDOM.hydrateRoot 函数(client 中调用)
- hydrateRoot:创建水合 Root,是在激活的模式下渲染 App
- 服务器端可以用 ReactDOM.renderToString 来进行渲染静态页面
- 路由需要在客户端和服务器端都配置,并且 API 是不同的