您的位置:首页 > Web前端 > React

react服务端渲染技术

2020-01-13 19:38 351 查看

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}

{routes} ) if (context.url) { res.writeHead(301, { Location: context.url }) res.end() } else { res.send(template({ body: html })); res.end() } }) server.listen(3000, function (err) { if (err) { console.log('服务器夭折了'); } else { console.log('服务器启动了'); } }); 添加routes.js 用于服务器兼客服端: import React from 'react'; import IndexQuanzi from './index_quanzi/index_quanzi.jsx'; import Error from './error.jsx'; import My from './my/my.jsx'; import coUserContract from './spread/coUserContract.jsx'; import {Route,Switch} from 'react-router-dom'; const routes =( ); export { routes } 添加template.js用于服务器发送: export default ({ body, title }) => { return ` 校园工作 ${body} `; }; 更改main.jsx文件: import {Promise} from 'es6-promise' import { BrowserRouter} from 'react-router-dom'; import ReactDOM from "react-dom"; import './iconfont/iconfont.css'; import React from 'react'; import { routes } from './routes' ReactDOM.render(( {routes} ),document.getElementById('init')); 项目启动方式 将 webpack.ssr.config.js 引入 package.json 使用 npm run ssr 先打包服务器资源,然后再npm run test/prd 打包 客户端资源, 将服务器打包的资源放入服务器指定位置能监听到客户端的请求, 然后再服务器开启server, server引入的template资源,template资源配置客户端打包好的js css. 然后客户端请求路由路径会经由服务器上的server获取再准备页面template+静态HTML发送给客户,客户收到的template中引入客户端打包的资源,完成SSR.
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(“My Page”);
res.write("

");
const stream = renderToNodeStream();
stream.pipe(res, { end: false });
stream.on(‘end’, () => {
res.write("");
res.end();
});
});

  • 点赞
  • 收藏
  • 分享
  • 文章举报
索利曼 发布了9 篇原创文章 · 获赞 0 · 访问量 75 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: