SSR的简单实现及配置
基本概念
客户端渲染
服务器端仅返回 JSON 数据.DATA和 HTML在客户端进行渲染
服务器端渲染
服务器端返回HTML,DATA和 HTML在服务器端进行渲染
客户端渲染存在的问题 1.首屏等待时间长,用户体验差 2.页面结构为空,不利于 SEO
React SSR 同构
同构指的是代码复用.即实现客户端和服务器端最大程度的代码复用
实现React SSR
引入要渲染的 React组件
通过 renderToString 方法将 React 组件转换为 HTML 字符串
将结果HTML字符串相应到客户端
server
import app from './http'; import React from 'react' import Home from '../share/pages/Home'; import { renderToString } from 'react-dom/server' app.get('/', (req, res)=>{ const content = renderToString(<Home />) res.send(` <html> <head> <title>SSR</title> </head> <body> <div id="root">${content}</div> <script src="bundle.js"></script> </body> </html> `) }) // http import express from 'express'; const app = express() // 服务器端程序实现静态资源访问功能,客户端 JavaScript 打包文件会被作为静态资源使用 app.use(express.static('public')) app.listen(3000, ()=>{ console.log('app is running') }) export default app; 复制代码
share
import React from 'react'; const Home = () => <div>Home</div> export default Home; 复制代码
client
import React from 'react'; import ReactDOM from 'react-dom'; import Home from '../share/pages/Home'; // 使用 hydrate 方法对组件进行渲染,为组件元素附加事件 // hydrate方法在实现渲染的时候,会复用原本已经存在的 DOM 节点,减少重新生成节点以及删除原本 DOM 节点的开销. ReactDOM.hydrate(<Home />, document.getElementById('root')); 复制代码
配置webpack
Node 环境不支持 ESModule 模块系统,不支持 JSX 语法.
项目启动命令配置
"scripts": { "dev": "npm-run-all --parallel dev:*", "dev:client-build": "webpack --config webpack.client.js --watch", "dev:server-run": "nodemon --watch build --exec \"node build/bundle.js\"", "dev:server-build": "webpack --config webpack.server.js --watch" }, 复制代码
webpack.base.js
module.exports = { // 指定当前为开发模式 mode: "development", module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: [ [ "@babel/preset-env", { useBuiltIns: "usage" } ], "@babel/preset-react" ] } } } ] } }; 复制代码
webpack.server.js
const path = require('path'); const merge = require('webpack-merge'); const baseConfig = require('./webpack.base'); const nodeExternals = require('webpack-node-externals'); const config = { // 指定项目打包目标支持环境 target: 'node', // 指定项目入口文件 entry: './src/server/index.js', // 指定文件打包位置及文件名称 output: { path: path.join(__dirname, 'build'), filename: 'bundle.js' }, externals: [nodeExternals()] } module.exports = merge(baseConfig, config); 复制代码
webpack.client.js
const path = require('path'); const merge = require('webpack-merge'); const baseConfig = require('./webpack.base'); const config = { // 指定项目入口文件 entry: './src/client/index.js', // 指定文件打包位置及文件名称 output: { path: path.join(__dirname, 'public'), filename: 'bundle.js' } } module.exports = merge(baseConfig, config);
作者:用户3613745411589
链接:https://juejin.cn/post/7021826345302753288