Webpack和react的项目一般打包出来的文件会包括 js css 文件, 在html里也就只需要用标签引入这几个文件就可以在客户端抓到JS信息之后动态渲染HTML,可是再右键点击显示网页源代码的时候是看不到HTML的静态信息,初步认为是不利于SEO, 在使用了服务端渲染技术(SSR)之后静态的页面会在服务端准备好之后再发送到前端展示,据前端组了解这也会大大加快页面的展示效果,React路由组建化使路由与组建一一对应,每次展示组建都会发送到客户端然后根据客户端机器性能进行渲染, SSR之后react提供reactDOM/server支持,使用 rendertostring, 或者rendertostaticmarkup, 前者SSR化动态react页面,后者静态页面(也就是没有用JS动态渲染/或者AJAX).
其中需要将 react组建规范化 在componentwillmount中不能涉及到DOM操作的逻辑,会导致react报错,将所有DOM操作和window,document操作都放入到ComponentDidMount中, React SSR会将ComponentWillMount以及之前的操作放在服务端(node.js)进行拼装,然后发给客户端在客户端进行ComponentDIDMount操作. 会需要在webpack中做并行打包服务端以及客户端内容,客户端JS包没变动,在服务端会开启NodeServer监听客户端浏览器GET方法返回对应路由的静态页面,页面中HTML根会有个reactroot属性,客户端那一边路由渲染的页面会更具这个reactroot属性来决定是否在客户端渲染willmount之前的静态页面还是直接调用componentdidmount(加快页面显示).
main.jsx中必须使用browerRouter来对应server.js中的staticRouter.
代码变更:
添加webpack.ssr.config.js 配置:
const webpack = require(‘webpack’);
const nodeExternals = require(‘webpack-node-externals’);
const path = require(‘path’);
var ExtractTextPlugin = require(‘extract-text-webpack-plugin’);
const CleanWebpackPlugin = require(‘clean-webpack-plugin’);
module.exports = {
entry: ‘./app/src/server.js’,
output: {
path: path.resolve(__dirname, ‘app/dist’),
filename: ‘server.js’,
publicPath: ‘/’
},
target: ‘node’,
externals: nodeExternals(),
plugins: [
// new CleanWebpackPlugin(path.resolve(__dirname, ‘dist/’)),
new webpack.ProvidePlugin({
‘fetch’: ‘imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch’,
qs: “qs”,
}),
new ExtractTextPlugin({
filename:“style-ssr.css”,
disable: process.env.NODE_ENV === “development”
}),
new webpack.DefinePlugin({
‘process.env.NODE_ENV’: JSON.stringify(‘production’),
pageUrl: JSON.stringify(‘http://www.anijue.com/p/q/campusjob-online-test/index.html#/’),
jsonpProxy: JSON.stringify(‘https://campus.alipay-eco.com’),//线上环境
logProxy: JSON.stringify(‘https://campus.alipay-eco.com’), // 线上环境
authUrl: JSON.stringify(‘https://campus.alipay-eco.com/topnews/user/auth’),
resumePageUrl: JSON.stringify(‘http://www.anijue.com/p/q/j3im6eja/index.html#/’),
appId: JSON.stringify(‘2016110702616399’),//线上appid 2016110702616399 sit测试appid 2016081601758195
cashAppid: JSON.stringify(‘2017090708600105’), //线上appid 2017090708600105 sit测试appid 2016081600255960
static_path: JSON.stringify(‘https://qufenqipublicrw.oss-cn-hangzhou.aliyuncs.com/fe’),
defaultImgSrc: JSON.stringify(‘https://qufenqipublicrw.oss-cn-hangzhou.aliyuncs.com/fe/job-default-log.png’),
huipinToDouble: JSON.stringify(‘https://huipinyun.cn/alicampus/toDouble.html’),
})
],
module: {
loaders: [
// { test: /.cssKaTeX parse error: Expected 'EOF', got '}' at position 83: …stcss-loader') }̲, //坑:不能用叹号链接,必…/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
use: [{
loader: “css-loader”
}, {
loader: “less-loader”
}],
// use style-loader in development
fallback: “style-loader”
})
},
{
test: /.js[x]?KaTeX parse error: Expected group after '_' at position 26: …: path.resolve(_̲_dirname, 'app'…/, loader: ‘url-loader?limit=8192’ },
{ test: /.(woff|woff2|eot|ttf|svg)(?.
∣
|
∣)/, loader: ‘url-loader’ },
{ test: /.json$/, loader: ‘json-loader’ }
]
}
};
添加server.js 用于服务器:
import template from ‘./template.js’;
import React from ‘react’;
import { matchPath, StaticRouter } from ‘react-router-dom’;
import ReactDOMServer from ‘react-dom/server’;
import {routes} from ‘./routes.js’;
import express from ‘express’;
const server = express();
server.use(’/dist’,express.static(’./app/dist’));
server.get(’’,(req, res) => {
const context = {}
const html = ReactDOMServer.renderToString(
<StaticRouter
location={req.url}
context={context}
REACT SSR Stream
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191205161154352.png)
支持流式输送就如同 node 里的 pipe, 将template传送给客户即便template的后面部分还没有静态化好,在流量被占用的情况下也可以表现优异
技术中心 > 趣校园前端项目服务端渲染技术 > image2018-2-2 15:16:28.png
流式的服务端渲染代码变更:
// using Express
import { renderToNodeStream } from “react-dom/server”
import MyPage from “./MyPage”
app.get("/", (req, res) => {
res.write(“