什么是客户端渲染
CSR: Client Side Rendering
服务器端仅返回 JSON 数据,DATA 和 HTML 在客户端进行渲染
什么是服务器端渲染
SSR: Server Side Rendering
服务器端返回 HTML,DATA 和 HTML在服务器端渲染
客户端渲染存在的问题
SPA 应用中服务器端渲染解决的问题
React SSR 同构
同构指的是代码复用,即实现客户端和服务器端最大程度的代码复用
import express from 'express';
const app = express();
app.use(express.static('public'));
app.listen(3000, () => console.log('app is running on 3000 port'));
export default app;
实现 React SSR
引入要渲染的 React 组件
通过 renderToString 方法将 React 组件转换为 HTML 字符串
将 Html 字符串想到客户端
renderToString 方法用于将 React 组件转换为 HTML 字符串,通过 react-dom/server 导入
Webpack 打包配置
问题: Node环境不支持 EsModule 模块系统,不支持 JSX 语法
项目启动命令配置
"dev:server-build": "webpack --config webpack.server.js --watch",
"dev:server-run": "nodemon --watch build --exec \"node build/bundle.js\"",
客户端 React 附加事件
实现思路分析
在客户端对组件进行二次“渲染”,为组件元素附加事件
目的:使用一个命令启动项目,解决多个命令启动的繁琐问题。通过 npm-run-all 工具实现
"dev": "npm-run-all --parallel dev:*",
服务器端打包文件体积优化
问题:在服务器端打包文件中,包含了Node系统模块。导致打包文件本身体积庞大。
解决:通过 Webpak 配置剔除打包文件中的 Node 模块。
// webpack.server.js
const nodeExternals = require('webpack-node-externals');
const config = {
externals: [nodeExternals()]
}
将启动服务器代码和渲染代码进行模块化拆分
优化代码组织方式,渲染 React 组件代码是独立功能,所以把它从服务器端入口文件中进行抽离。
实现思路分析
编写路由规则
import Home from '../share/pages/Home';
import List from '../share/pages/List';
export default [{
path: '/',
component: Home,
exact: true
}, {
path: '/list',
...List
}]
实现服务器端路由
Express 路由接收任何请求
Express 路由接收所有 get 请求,服务器 React 路由通过请求路径匹配要进行渲染的组件
app.get('*', (req, res) => {});
实现思路分析
实现客户端 Redux
实现服务器端 Redux
服务器端 Store 数据填充
问题:服务器端创建的 store 是空的,组件并不能从 store 中获取到任何数据
解决:服务器端在渲染组件之前获取到组件所需要的数据
警告原因:客户端 Store 在初始状态下是没有数据的,在渲染组件的时候生成的是空 ul ,但服务器端是先获取数据再进行的组件渲染,所以生成的是有子元素的 ul, hydrate 方法在对比的时候发现两者不一致,所以报了个警告。
解决思路:将服务器端获取到的数据回填给客户端,让客户端拥有初始数据
防范 XSS 攻击