Open linwu-hi opened 1 year ago
服务端渲染(SSR)是一种用于处理页面的技术,它在服务器端构建HTML结构并将完整的交互式页面发送到浏览器,然后将状态和事件绑定到该页面。SSR主要解决了两个关键问题:
搜索引擎爬虫可以直接查看完全渲染的页面,而客户端渲染(Client-Side Rendering,简称CSR)可能会导致搜索引擎无法获取页面内容。
CSR可能导致首屏白屏,用户体验较差。SSR可以在服务器端渲染首屏,提高加载速度。
我们通过Express创建一个服务器,用于监听3000端口的请求,并在根目录请求时返回HTML页面。
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send(` <html> <head> <title>SSR Demo</title> </head> <body> Hello world </body> </html> `); }); app.listen(3000, () => console.log('Example app listening on port 3000!'));
我们将在服务器端编写React代码,并在app.js中引用它。
app.js
为了使服务器能够识别JSX,我们需要使用Webpack对项目进行打包转换。创建一个名为webpack.server.js的配置文件,并进行相关配置。
webpack.server.js
const path = require('path'); const nodeExternals = require('webpack-node-externals'); module.exports = { target: 'node', mode: 'development', entry: './app.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'] } }]], }, }, ], }, };
renderToString
我们借助react-dom提供的renderToString方法,将React组件渲染为HTML字符串。
react-dom
import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import Home from './src/containers/Home'; const app = express(); const content = renderToString(<Home />); app.get('/', (req, res) => { res.send(` <html> <head> <title>SSR Demo</title> </head> <body> ${content} </body> </html> `); }); app.listen(3001, () => console.log('Example app listening on port 3001!'));
同构是指一套React代码在服务器端和客户端都能运行。在同构中,服务端渲染完成页面结构,而浏览器端渲染完成事件绑定和一些交互。这种方式既可以提高首屏加载速度,又能保持页面的交互性。
在React应用中,通常会存在多个页面和路由的情况。为了在服务端渲染中处理路由,需要配置路由信息。
:
import React from 'react'; import { Route } from 'react-router-dom'; import Home from './containers/Home'; export default ( <div> <Route path="/" exact component={Home}></Route> </div> );
然后,可以通过index.js引用路由信息:
index.js
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import Router from '../Routers'; const App = () => { return ( <BrowserRouter> {Router} </BrowserRouter> ); }; ReactDom.hydrate(<App />, document.getElementById('root'));
在服务端渲染时,每个Route组件外面包裹着一层div,但在服务端返回的代码中并没有这个div。这可能会导致浏览器端渲染时出现问题。为了解决这个问题,我们需要在服务端执行一遍路由信息,使用StaticRouter来替代BrowserRouter,并通过context参数进行参数传递。
StaticRouter
BrowserRouter
context
import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom'; import Router from '../Routers'; const app = express(); app.use(express.static('public')); app.get('/', (req, res) => { const content = renderToString( <StaticRouter location={req.path} context={{}}> {Router} </StaticRouter> ); res.send(` <html> <head> <title>SSR Demo</title> </head> <body> <div id="root">${content}</div> <script src="/index.js"></script> </body> </html> `); }); app.listen(3001, () => console.log('Example app listening on port 3001!'));
props
store
renderToString()
服务端渲染(SSR)
服务端渲染简介
服务端渲染的问题
SEO问题
首屏加载问题
实现服务端渲染(SSR)
创建Express服务器
我们将在服务器端编写React代码,并在
app.js
中引用它。使用Webpack进行打包
使用
renderToString
渲染React组件实现服务端和客户端共用一套代码
同构概念
处理路由问题
:
然后,可以通过
index.js
引用路由信息:解决路由渲染问题
服务端渲染的工作流程
props
、context
或store
等形式传递给React组件。renderToString()
将React组件渲染为HTML字符串。参考文献