react服务端渲染趟坑之旅

本文记录了作者在实现React服务端渲染过程中遇到的挑战和解决方案。从理解SSR原理开始,逐步解决样式文件、资源文件处理,以及返回完整HTML格式的问题。重点介绍了渲染数据的策略,使用状态容器在服务端获取数据并传递给前端。最后提到了使用renderToNodeStream以提高首屏加载速度。
摘要由CSDN通过智能技术生成

起因:前段时间用react完成了个人博客,部署到线上,加载速度,首屏体验是在是感人,哎。

决定:之前听说过ssr,想试试但是一直没有去深入研究,ssr对于首屏速度,加载到,还有SEO都很友好,于是决定试试。

过程:ssr确实挺多坑的,首先你得领会它的原理,其实就是快照,把当前快照反馈给用户。对于一些样式文件、资源之类的,服务器是不识别的,需要进行预处理。所以我就去找第三方包,用的也不是特别顺畅,就去读他们的源码,才是弄明白,反正这个过程是断断续续弄了一个月多,挺艰辛的。

技术栈:webpack4.x + react16.x + redux + less

tips:对于服务端渲染不是特别理解的,可以看下vue服务端渲染

准备工作

一份build好的react的项目文件

正式开始

1. 本地起node服务,把build文件本地跑起来
//server/server.js
const express = require("express");
const userRoute = require("../src/route");
const app = express();
const path = require('path');

// 映射到build后的路径
//设置build以后的文件路径 项目上线用
app.use((req, res, next) => {
   
    if (req.url.startsWith('/static/')) {
   
        return next()
    }
    return res.sendFile(path.resolve('build/index.html'))
})
app.use('/',express.static(path.resolve(__dirname,'../build')))

app.listen("9000",function(){
   
    console.log("open Browser http://localhost:9000");
});

在pageage.json配置下

 "scripts": {
   
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js --env=jsdom",
    "server": "nodemon server/server.js"
  },

运行npm run server,浏览器查看localhost:9000

在这里插入图片描述

在node文件中我们要引入react等,需要用的ES6/7的语法,与node的commonjs规范违背。所以我们需要解析语法转化成commonjs。同时安装cross-en包,设置运行环境为test,不然会报错。
安装babel-node

cnpm i @babel/core @babel/node -g
"scripts": {
   
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js --env=jsdom",
    "server": "cross-env NODE_ENV=test nodemon --exec babel-node server/server.js"
  },

2.ReactDOMServer.renderToString

React.createElement把React类进行实例化,实例化后的组件就可以进行mount操作了,在浏览器环境我们是使用ReactDOM.render()来进行挂载操作的。ReactDOMServer.renderToString则是把React实例渲染成HTML标签。接下里就需要吧index.js里面代码搬到server.js里面,渲染成html返回给前端就OK! 进行代码改造,完成后如下:

//server/server.js
const express = require("express");
const Route = require("../src/route");
const app = express();
const path = require('path');

// 映射到build后的路径
//设置build以后的文件路径 项目上线用
app.use((req, res, next) => {
   
    if (req.url.startsWith('/static/')) {
   
        return next()
    }
const context = {
   }
    const ReactSSR = renderToString(
        (<Provider store={
   store}>
            <StaticRouter
                location={
   req.url}
                context={
   context}>
                <Route />
            </StaticRouter>
        </Provider>)
    )
    res.send(ReactSSR)
})
app.use('/',express.static(path.resolve(__dirname,'../build')))

app.listen("9000",function(){
   
    console.log("open Browser http://localhost:9000");
});

此时代码用renderToString()处理后返回给前端,npm run start 运行看看,发现控制台报错。
[外链图片转存失败(img-9bI0dooH-1569157416526)(https://raw.githubusercontent.com/lourain/pic-bed/master/E8A66803-9D29-4DDE-9D9D-50B016139776.png)]
是css报错,服务端中不识别样式文件,我们要处理下。

2. 处理样式文件

我们需要安装一个包css-modules-require-hook

cnpm i css-modules-require-hook -S-D

安装好依赖以后,我们需要引入配置,并新建crmh.conf.js钩子文件进行配置

[外链图片转存失败(img-xlU335HS-1569157491605)(https://raw.githubusercontent.com/lourain/pic-bed/master/QQ20190314-150117@2x.png)]

const lessParser = require('postcss-less').parse;//把less解析成postcss语法
module.exports = {
   
    extensions: ['.less','.css'],
    generateScopedName: '[path][name]__[local]--[hash:base64:5]',//class名称必须与webpack内的设置保持一致
    processorOpts: {
   parser: lessParser},
    
}
//server/server.js
// 处理css
//一定要放置在文件最前面
import csshook from 'css-modules-require-hook/preset';
...
...

处理好css后,运行cnpm run server,此时看到报错:

[外链图片转存失败(img-mgtZc6rx-1569157575940)(https://raw.githubusercontent.com/lourain/pic-bed/master/QQ20190314-171123%402x.png)]

图片,资源类文件报错

3. 处理图片资源文件

需要安装包

cnpm install asset-require-hook --save 

对server.js进行配置

//server/server.js
// 处理css
//一定要放置在文件最前面
import csshook from 'css-modules-require-hook/preset';
// 处理图片
import assethook from 'asset-require-hook';
...
...
assetHook({
   
    extensions: ['jpg', 'png', 'webp', 'ttf'],
    name: 'static/media/[name].[hash:8].[ext]'
})
···

然后我们再运行一下,查看浏览器network的response
[外链图片转存失败(img-CNLquPQn-1569157282817)(https://raw.githubusercontent.com/lourain/pic-bed/master/QQ20190314-171123%402x.png)]

发现返回的仅仅是一个div&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值