CSR和SSR
客户端渲染CSR
服务器向浏览器发送空的HTML文档-> 然后浏览器下载JS文件 -> 浏览器执行React代码->页面渲染完毕
服务器端渲染SSR
服务器直接发送HTML文档
比较:
我们可以看出SSR架构下页面非常快,只需要下载HTML,也就是说首屏加载非常快
SEO 百度爬虫是认识HTML,也就是说只有SSR在百度会有一个好的排名
配置服务器webpack
首先我们在src目录下创建index.js 简单的服务器代码
const express = require('express') const app = express() app.get('/', (req, res) => { res.send( ` <html> <head> <title>React SSR</title> </head> <body> <h1>React SSR</h1> </body> </html> ` ) }) var server = app.listen(3000)
修改package.json
"start": "node ./src/index.js"
npm run start 运行
我们能在3000页面看到React SSR
现在我们通过wepack打包服务器代码
我们先安装webpack webpack-cli babel-loader babel-core babel-preset-env babel-preset-react babel-preset-stage-0 webpack-node-externals
然后在跟目录创建webpack.config.server.js配置如下
const path = require('path') const nodeExternals = require('webpack-node-externals') module.exports = { target:'node', mode:'development', entry:'./src/index.js', output:{ filename:'bundle.js', path: path.resolve(__dirname, 'build') }, externals:[nodeExternals()], module:{ rules:[ { test:/\.js?$/, loader:'babel-loader', exclude:/node_modules/, options: { presets:['react','stage-0',['env', { targets: { browsers: ['last 2 versions'] } }]] } } ] } }
我们把src/index.js打包到build/bundle.js下然后修改package.json
"start": "node ./build/bundle.js"
var express = require('express') import React from 'react' import {renderToString} from 'react-dom/server' import Home from './pages/home' var app = express() app.get('/', function (req, res) { res.send( `<html> <head> <title>hello</title> </head> <body> <h1>first lesson</h1> <p>hello world</p> ${renderToString(<Home/>)} </body> </html>` ) }) var server = app.listen(3000)
接着build & start 3000端口页面会出现Home组件内容,查看浏览器源代码,我们可以看到Home组件源代码
到此我们已经实现了基本的React在服务器端渲染
优势:react的服务器端渲染也是使用React虚拟DOM,加快了首屏加载速度,SEO
劣势:服务端端渲染react代码在服务器上执行,消耗服务器性能
同构技术
首先我们先修改HomeComponent代码,加个Button.click事件,然后在浏览器发现click事件不触发
因为renderToString方法不会把事件渲染出来
我们可以让react在服务器端执行一次,然后在客户端执行一次,这就是同构的概念
首先我们在根目录下创建public/index.js 文件。里面一句console.log代码
接下来我们使用在src/index.js目录下添加如下代码,
app.use(express.static('public'))
页面引用<script src="/index.js"></script>
我们再次打包编译就能看到控制台打印一句话
我们到此浏览器可以执行一段JS文件
具体服务器会到publick找到js文件 浏览器根据script找到js文件,于是浏览器就能执行js文件
我们现在能执行js文件了,那么我们开始让React代码在浏览器运行
创建src/client/index.js 代码如下
import React from 'react' import ReactDOM from 'react-dom'; import Home from '../src/pages/home' ReactDOM.render(<Home/>, document.getElementById('root'))
接下来在跟目录添加webpack.client.js
const path = require('path') module.exports = { mode:'development', entry:'./src/client/index.js', output:{ filename:'index.js', path: path.resolve(__dirname, 'public') }, module:{ rules:[ { test:/\.js|jsx?$/, loader:'babel-loader', exclude:/node_modules/, options: { presets:['react','stage-0',['env', { targets: { browsers: ['last 2 versions'] } }]] } } ] } }
打包代码执行
这时候浏览器会warning因为react在服务器渲染一次在客户端渲染一次也就是同构的话。我们可以修改client/index.js
ReactDOM.hydrate(<Home/>, document.getElementById('root'))
到此我们可以在实现同构了,通过打包一次服务器端代码一个客户端代码,然后服务器通过script引入 实现了Button.click的点击事件了
代码优化
首先我们修改下代码结构,我们在之前创建的index.js文件下是在src目录下,我们优化下目录结构把index.js文件移到src/server/index.js文件,下具体文件格式如下

优化webpack配置文件
安装 webpack-merge
跟目录创建webpack.base.js代码提取webpack.client和webpack.server公共代码具体代码
webpack.base.js
module.exports = { module:{ rules:[ { test:/\.js|jsx?$/, loader:'babel-loader', exclude:/node_modules/, options: { presets:['react','stage-0',['env', { targets: { browsers: ['last 2 versions'] } }]] } } ] } }
webpack.client.js
const path = require('path') const merge = require('webpack-merge') const config = require('./webpack.base') const clientConfig = { mode:'development', entry:'./src/client/index.js', output:{ filename:'index.js', path: path.resolve(__dirname, 'public') } } module.exports = merge(config, clientConfig)
webpack.server.js
const path = require('path') const nodeExternals = require('webpack-node-externals') const merge = require('webpack-merge') const config = require('./webpack.base') const serverConfig = { target:'node', mode:'development', entry:'./src/server/index.js', output:{ filename:'bundle.js', path: path.resolve(__dirname, 'build') }, externals:[nodeExternals()] } module.exports = merge(config, serverConfig)
此次我们可以对服务器端渲染有了新的了解
服务器端运行React代码渲染HTML->发送HTML给浏览器->浏览器接受HTML展示页面内容->浏览器加载JS文件->JS文件在浏览器重新执行->JS中的React接管页面的操作
浙公网安备 33010602011771号