React 服务器端渲染概念回顾
什么是客户端渲染CSR(Client Side Rendering)
服务器端只返回json数据,Data和Html的拼接在客户端进行(渲染)。
什么是服务器端渲染SSR(Server Side Rendering)
服务器端返回数据拼接过后的HTML,Data和Html的拼接在服务器端进行(渲染)。
使用react实现的应用都是单页应用(Singe Page Application),都属于是客户端渲染。
为什么要实现服务器端渲染,SPA的服务器端渲染旨在解决哪些问题呢。
客户端首页渲染时间长,大部分时间处于页面外链的加载等待状态,用户体验差。
页面结构是空的,不利于网站的SEO
SSR同构,同构指的是代码复用,即实现客户端和服务器端最大程度的的代码复用。
原生实现
项目结构
react-ssr
- src 源代码文件夹
- client 客户端代码
- server 服务器端代码
- share 同构代码
三步快速实现React SSR
引入要渲染的React组件
通过renderToString方法将React 组件转换为HTML 字符串
renderToString方法用于将React组件转换成HTML字符串,可通过react-dom/server 导入
将结果HTML字符串响应到客户端
首先我们需要使用express快速搭建一个server服务器
// http.js
import express from 'express'
const app = express()
app.listen(3000, () => console.log('app is running on port 3000'))
export default app
将同构代码,主要为页面组件代码,放到share 文件夹下
webpack打包配置
这时候我们就像通过node来运行我们的express服务器是会报错的:
$ node src/server/index.js
(node:8130) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/Users/huiquandeng/projects/lg-fed-lp/my-module/react-ssr/src/server/index.js:1
import Home from '../share/pages/Home'
^^^^^^
SyntaxError: Cannot use import statement outside a module
问题:nodejs环境不支持ESModule模块系统,不支持JSX语法。
所以需要webpack工具使用babel插件对其进行转换。
const path = require('path')
module.exports = {
mode: 'development',
target: 'node',
entry: './src/server/index.js',
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
}
]
}
}
在 package.json中配置运行命令:
"scripts": {
"dev:server-build": "webpack --config webpack.server.js"
}
此时即可运行打包命令生成bundle.js 文件到build 目录下,
这时使用node命令允许该服务器就不会报错了。
$ node build/bundle.js
app is running on port 3000
尝试访问应用页面,发现报错React模块未定义。
$ node build/bundle.js
app is running on port 3000
ReferenceError: React is not defined
at eval (webpack://react-ssr/./src/server/index.js?:9:96)
回到server 的index.js 文件中,我们引入React即可。
此时服务器已经可以正常渲染React 组件中的内容。
改进: 这时候我们没改动一次代码要想页面内容生效,都需重新运行一下打包命令,这个操作可以交给我们的程序自主监测运行,减少我们的重复的手工操作,提升开发效率。
配置项目启动命令
配置服务器端webpack打包命令:
"dev:server-build": "webpack --config webapck.server.js --watch"
打包命令加入--watch 参数,可以让webpack监控文件的更改重新执行build打包命令生成build目录下多的文件。
配置服务端启动命令:
"dev:server-run": "nodemon --watch build --exec \"node build/bundle.js\""
该命令使用了nodemon进行node程序的监控,通过--watch 监控指定文件夹中文件的变化,当有变化时重新运行服务器启动命令:node build/bundle.js。
此时开两个终端分别运行以上两个命令即可实现文件变化的监控。
为组件元素附加事件的方式
思路: 在客户端对组件进行二次渲染,为组件元素附加事件。
客户端二次渲染的方法:hydrate
使用hydrate 方法对组件进行渲染,为组件元素附加事件。
该方法在实现渲染的时候,会复用原本已经存在的DOM节点,减少重新生成节点以及删除原本DOM节点的开销。
可