React服务端渲染+pm2自动化部署

本文详细介绍了如何实现React服务端渲染(SSR),探讨了SSR的原因,比较了客户端渲染与服务端渲染的区别,并通过实战演示了如何使用webpack打包、在服务端访问文件、运用ReactDOMServer进行渲染。此外,还讲解了使用pm2进行服务器自动化部署的步骤,包括域名代理等关键环节。
摘要由CSDN通过智能技术生成

这里写图片描述

本文是直接着手SSR部分的并通过实战讲述自己遇到的一些问题和方案,需要大家有一定的React,node和webpack基础能力。skr,skr。

服务端渲染

Server Slide Rendering服务端渲染,又简写为SSR,他一般被用在我们的SPA(Single-Page Application),即单页应用。

为什么要用SSR?

首先我们需要知道SSR对于SPA的好处优势是什么。

  • 更好的SEO(Search Engine Optimization)SEO是搜索引擎优化,简而言之就是针对百度这些搜索引擎,可以让他们搜索到我们的应用。这里可能会有误区,就是我也可以在index.html上写SEO,为什么会不起作用。因为React、Vue的原理是客户端渲染,通过浏览器去加载js、css,有一个时间上的延迟,而搜索引擎不会管你的延迟,他就觉得你如果没加载出来就是没有的,所以是搜不到的。
  • 解决一开始的白屏渲染,上面讲了React的渲染原理,而SSR服务端渲染是通过服务端请求数据,因为服务端内网的请求快,性能好所以会更快的加载所有的文件,最后把下载渲染后的页面返回给客户端。

上面提到了服务端渲染和客户端渲染,那么它们的区别是什么呢?

客户端渲染路线:

  1. 请求一个html
  2. 服务端返回一个html
  3. 浏览器下载html里面的js/css文件
  4. 等待js文件下载完成
  5. 等待js加载并初始化完成
  6. js代码终于可以运行,由js代码向后端请求数据( ajax/fetch )
  7. 等待后端数据返回
  8. react-dom( 客户端 )从无到完整地,把数据渲染为响应页面

服务端渲染路线:

  1. 请求一个html
  2. 服务端请求数据( 内网请求快 )
  3. 服务器初始渲染(服务端性能好,较快)
  4. 服务端返回已经有正确内容的页面
  5. 客户端请求js/css文件
  6. 等待js文件下载完成
  7. 等待js加载并初始化完成
  8. react-dom( 客户端 )把剩下一部分渲染完成( 内容小,渲染快 )

其主要区别就在于,客户端从无到有的渲染,服务端是先在服务端渲染一部分,在再客户端渲染一小部分

我们怎么去做服务端渲染?

我们这里是用express框架,node做中间层进行服务端渲染。通过将首页进行同构处理,让服务端,通过调用ReactDOMServer.renderToNodeStream方法把Virtual DOM转换成HTML字符串返回给客户端,从而达到服务端渲染的目的。

这里项目起步是已经做完前端和后端,是把已经写好的React Demo直接拿来用

服务端渲染开始

既然是首页SSR,首先我们要把首页对应的index.js抽离出来放入我们服务端对应的server.js,那么index.js中组件对应的静态css和js文件我们需要打包出来。

用webpack打包文件到build文件夹

我们来运行npm run build

我们可以看到两个重要的文件夹,一个是js文件夹,一个是css文件夹,他就是我们项目的js和css静态资源文件

将打包后的build文件能在服务端server.js中访问到

因为是服务端,我们需要用到express

import express from 'express'
import reducers from '../src/reducer';

import userRouter from './routes/user'
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import model from './model'
import path from 'path'
import https from 'http'
import socketIo from 'socket.io'


const Chat = model.getModel('chat')
//新建app
const app = express()

//work with express
const server = https.Server(app)
const io = socketIo(server)
io.on('connection',function(socket){
   
  socket.on('sendmsg',function(data){
   
    let {from,to,msg} = data
    let chatid = [from,to].sort().join('_')
    Chat.create({chatid,from,to,content:msg},function(e,d){
   
      io.emit('recvmsg',Object.assign({},d._doc))
    })
    // console.log(data)
    // //广播给全局
    // io.emit('recvmsg',data)
  })
})

app.use(cookieParser())
app.use(bodyParser.json())
app.use('/user',userRouter)
app.use(function(req,res,next){
   
  if(req.url.startsWith('/user/') || req.url.startsWith('/static/')){
    return next()
  }
  //如果访问url根路径是user或者static就返回打包后的主页面
  return res.sendFile(path.resolve('build/index.html'))
})
//映射build文件路径,项目上要使用
app.use('/',express.static(path.resolve('build')))


server.listen(8088, function () {
   
    console.log('开启成功')
})
  • 主要看上面的app.use('/',express.static(path.resolve('build')))res.sendFile(path.resolve('build/index.html'))这两段代码。
  • 他们把打包后的主页放入服务端代码中返回给客户端。
  • 因为上面我用了import代码,所以我们在开发环境中需要用到babel-cli里的babel-node来编译。
  • 安装npm --registry https://registry.npm.taobao.org i babel-cli -S`,大家如果觉得这样切换源麻烦,可以下个nrm,360度无死角切换各种源,好用!
  • 我们需要修改package.json的启动服务器的npm scripts"server": "NODE_ENV=test nodemon --exec babel-node server/server.js"
  • cross-env跨平台设置node环境变量的插件。
  • nodemon和supervisor一样是watch服务端文件,只要一改变就会重新运行,相当于热重载。nodemon更轻量
  • 最后我们来跑一下npm run server,就能看到服务端跑起来了。

ReactDOMServer.renderToString/ReactDOMServer.renderToNodeStream

  • 这里我们先讲一下在浏览器中React.createElement把React的类进行实例化,实例化后的组件可以进行mount,最后通过React.render渲染到我们的客户端浏览器界面。
  • 而在服务器中我们可以通过 renderToString或者renderToNodeStream方法把React实例化的组件,直接渲染生成html标签。那么这俩个有什么区别呢?
  • renderToNodeStream是React 16最新发布的东西,它支持直接渲染到节点流。渲染到流可以减少你的内容的第一个字节(TTFB)的时间,在文档的下一部分生成之前,将文档的开头至结尾发送到浏览器。 当内容从服务器流式传输时,浏览器将开始解析HTML文档。速度是renderToString的三倍,所以我们在这里使用renderToNodeStream
import express from 'express'
import React from 'react'
import {renderToStaticMarkup,renderToNodeStream} from 'react-dom/server'

import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import {StaticRouter} from 'react-router-dom'
import {
  createStore,
  applyMiddleware,
  //组合函数用的
  compose
} from 'redux';
import App from '../src/App'
import reducers from '../src/reducer';

import userRouter from './routes/user'
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import model from './model'
import path from 'path'
import https from 'http'
import socketIo from 'socket.io'

const Chat = model.getModel('chat')
//新建app
const</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值