前言
什么是服务端渲染呢?在使用单页面应用框架(如:react、vue等)时,我们的dom树的构建构建流程是
加载js->请求所需数据->渲染dom树
,
也就是说我首次http请求加载过来的仅仅是一个空壳子。如下
1
2
3
4
5
6
7
8
9<!doctype html> <html> <title>ssr</title> <body> <div id="root"></div> </body> <script src="/vendor/bundle.js"></script> </html>
这样的缺点有哪些?
1、不利于SEO (搜索引擎优化),搜索引擎在抓取我们的网页的时候,获取的仅仅是这一点信息,当我们的用户去搜索我们的网站的时候,相关信息就很少。
2、客户端渲染,当我们打包的js文件过大的时候,加载延迟会很大,白屏时间会很长,用户体检较差,有些用户不愿意等,就关闭了我们的网页,达不到预期的宣传效果。
解决思路
既然这种加载的流程不行,我们就换种方式加载。考虑让一次http加载出更详细的网页信息。这里就要用到服务端渲染
了。
想一想传统的react、vue页面 是如何显示在浏览器中的:
1、用webpack、gulp等这些前端构建工具对 我们写好的页面进行打包
2、会用一个render函数来渲染dom
那么我们就在服务端模拟这个流程,将渲染出来的html保存在一个变量里,然后将这些数据返回给客户端,这样不就可以显示解决上面的问题了吗
实践
在react的刚好提供了这样一个服务端渲染的函数 renderToString
它放在react-dom/server
里 他会对react组件进行渲染
试一下,我们要在服务端安装 react ,而且 通常我们的react里包含了许多es6一些语法 :箭头函数、import等。我们也要在服务端支持这些语法。
先安装babel相关
1
2yarn add @babel/register @babel/preset-react @babel/preset-env
以及babel的plugins:@babel/plugin-transform-runtime用与运行时转换
1
2yarn add @babel/plugin-transform-runtime
在服务端代码入口的第一行注册babel
1
2
3
4
5
6require('@babel/register')({ presets: ['@babel/preset-react','@babel/preset-env'],//转换es6以及react jsx plugins: ["@babel/plugin-transform-runtime"] });
这样就可以在服务端代码中使用 es6语法了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21const express = require('express'); const app = express(); const React = require('react'); const {renderToString} = require('react-dom/server'); function App(){ return (<div>hello world</div>) } app.get('/',function(req,res){ const content = renderToString(<App />)); res.send(` <!doctype html> <html> <title>ssr</title> <body> <div id="root">${content}</div> </body> </html> `); });
我们发现可以正常显示了 hello world
但是这里生成的仅仅是静态的html 没有交互能力,我们需要为他添加交互能力 JavaScript 即同构
简单来说就是“同种结构的不同表现形态
”。在这里我们用更通俗的大白话来解释react同构就是:
同一份react代码在服务端执行一遍,再在客户端执行一遍。
我们重新分割一下代码
App.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import React from 'react'; import Generetor from '../app/src/components/Dragging/generator'; class App extends React.Component { sayHello(){ alert('hello') } render(){ return ( <div onClick={this.sayHello()}> hello world </div> ); } } export default App;
ssr_server.js
1
2
3
4
5import React from "react"; import App from "./App"; module.exports = <App/>;
ssr_clients.js
1
2
3
4
5
6import React from 'react'; import {hydrate} from 'react-dom'; import 'antd/dist/antd.css'; import App from './App'; hydrate(<App/>,document.getElementById("root"));
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import App from './ssr_server' const express = require('express'); const app = express(); const React = require('react'); const {renderToString} = require('react-dom/server'); app.get('/',function(req,res){ const content = renderToString(<App />)); res.send(` <!doctype html> <html> <title>ssr</title> <body> <div id="root">${content}</div> </body> </html> `); });
我们用webpack将 ssr_client打包生成js 插入到html中即可
我们配置服务端wepack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60const path = require('path'); const nodeExternals = require('webpack-node-externals'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const MiniCssPlugin = require("mini-css-extract-plugin"); module.exports = { // 入口文件 entry: './SSR/ssr_client.js', output: { filename: 'bundle.js', path: path.join(__dirname, '/public/dist/ssr') }, module: { // 配置相应的规则 rules: [ { test: /.css$/, use: [ MiniCssPlugin.loader,'css-loader', 'postcss-loader'] }, { test: /.js[x]?$/, use: { loader:'babel-loader', options: { presets: ["@babel/react", "@babel/preset-env"], plugins: ["@babel/plugin-proposal-class-properties"] } }, exclude: /node_modules/, }, { test: /.less$/, use: [MiniCssPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1 } }, 'less-loader'], },{ test: /.(png|jpe?g)/i, use: [ { loader: "url-loader", options: { name: "./img/[name].[ext]", limit: 10000 } }, { loader: "img-loader" } ] } ] }, target: 'node', //不将node自带的诸如path、fs这类的包打进去 // 配置相应的插件 plugins: [ new MiniCssPlugin({ filename:'bundle.css' }) ] };
由于打包过程中会遇到es7、es6语法 需要安装@babel/plugin-proposal-class-properties支持es7 es6的之前装过了,
打包之后生成css 以及js文件
执行
1
2webpack --config webpack.config.js
产出
___dist
______ssr
________bundle.js
________bundle.css
修改app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import App from './ssr_server' const express = require('express'); const app = express(); const React = require('react'); const {renderToString} = require('react-dom/server'); app.get('/',function(req,res){ const content = renderToString(<App />)); res.send(` <!doctype html> <html> <title>ssr</title> <head> <link rel="stylesheet" type="text/css" href="/ssr/bundle.css" > </head> <body> <div id="root">${content}</div> </body> <script src="/ssr/bundle.js"></script> </html> `); });
启动服务器 访问 localhost:3000即可看到服务端渲染的界面
最后
以上就是鲤鱼宝贝最近收集整理的关于react 服务端渲染 基本操作的全部内容,更多相关react内容请搜索靠谱客的其他文章。
发表评论 取消回复