大前端 - react - 服务端渲染- ReactSSR

1.ReactSSR相关观念回顾

1.1. 什么是客户端渲染(CSR)

CSR: Client Side Rendering

服务器端仅返回json数据就可以了,data(数据)和html的在客户端进行渲染。

数据和html 的拼接是在客户端完成的,是在浏览器当中使用javascript来完成的,对服务器端来说,只需要返回json数据就可以了。

1.2. 什么是服务端渲染(SSR)

SSR: Server Side Rendering

服务端返回html,data和html的拼接过程在服务器端进行渲染。

就是说当客户端向服务端发送请求,服务器端接受到这个请求以后,在服务器端获取到数据,并且把这个数据和html拼接好,最后再把拼接好的结果一起返回给客户端。客户端只需要把接收到html 显示出来就好了。

1.3.客户端渲染存在的问题:
  1. 首屏等待时间长,用户体验差
  2. 页面结构为空,不利于seo。

SPA应用中服务器端渲染解决的问题:

客户端渲染过程:

  1. 首先客户端向服务器端发送请求获取首页面,当服务端收到请求以后,它对客户端做出了响应,在这个响应的内容当中,只包含了一个空的html文档,在这个文档当中,只包含了一些css外链,和js外链,在这个请求的过程,用户是处于等待的状态的,在页面当中是没有任何内容的,接下来,浏览器要去执行这个空的html文档,在执行的过程当中,它又要去服务端发送请求,获取对应的外链文件,在获取外链文件的过程中,客户端还是处于等待的状态的,在页面当中仍然看不到内容,当客户端把外链文件加载完成之后,就会去执行对于的js文件,在执行js文件的过程中,又要向服务器端发送请求,获取当前这个页面所需要的数据,在请求数据的过程中,客户端依然什么都看不到,当数据请求完成之后,又要使用javascript把这个json数据和html拼接好,最终把拼接好的结果显示在页面中。直到最后一步,用户在浏览器中看到页面。
  2. 使用csr,可以看到大部分的时间用户都是处于等待的状态,所以用户体验不要。这是存在的第一个问题,首屏等待时间长,用户体验差第2个问题,因为页面结构是空的,空的页面结构是不利于seo的,搜索引擎的爬虫工具在爬取页面内容的时候,由于你的页面结构为空,所以爬取不到任何的内容。

在这里插入图片描述
服务器端渲染的过程:

  1. 首先客户端向服务器端发送请求,服务器端收到请求之后,服务器端把数据和html拼接好,那么把拼接的结果返回给了客户端,请求的过程和响应的过程浏览器是处于等待的状态的。
  2. 接下来,浏览器去执行服务器端给它返回的结果,在响应的html文档当中,是包含了html与数据的,所以此时用户是能够看到这个页面内容的,只不过现在这个页面当中它只有静态的html内容,它并没有动态的效果,当浏览器去执行这个文档的时候,它又要去请求js文件了,当这个js文件请求成功以后,那么浏览器开始执行这个js文件,当浏览器把这个js文件执行完之后 ,在用户的界面中就有动态效果了。
  3. 通过ssr这个渲染的方法,用户早早的就看到了用户界面了,只不过这个html页面没有动态效果,只有我再去请求对应的js文件,执行了这个js文件之后,用户看到的才是一个完整的html 页面,但是不管怎么样,相对于客户端渲染来讲用户早早的看到了用户界面了。所以解决了第一个问题:首屏等待时间长,用户体验差的问题。那么对于服务器端来讲,返回的是一个完整的html页面,在我们查看网页的源代码的时候,是能够看到这个网站当中的内容的,所以当搜索引擎来爬取你的内容的时候,搜索引擎的爬虫工具也可以看到网站当中有什么内容,从而解决seo的问题这是服务器端渲染的过程。

在这里插入图片描述

1.4 React SSR同构

同构指的是:代码复用,即实现客户端和服务端最大程度的代码复用。

在实现服务器端渲染的过程中,客户端渲染也是需要实现的,那么在实现的过程中,我们要实现客户端路由,服务器端路由,客户端redux和服务器端redux,那么在实现的过程中有很多的代码可以复用。他的核心在于代码的复用。

2.ReactSSR服务端渲染实战

2.1 项目初始化:

项目结构:
在这里插入图片描述

package.json

{
   
  "name": "ssr-guide",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
   
    "dev": "npm-run-all --parallel dev:*",
    "dev:server-run": "nodemon --watch build --exec \"node build/bundle.js\"",
    "dev:server-build": "webpack --config webpack.server.js --watch",
    "dev:client-build": "webpack --config webpack.client.js --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
   
    "@babel/cli": "^7.10.3",
    "@babel/core": "^7.10.3",
    "@babel/polyfill": "^7.10.4",
    "@babel/preset-env": "^7.10.3",
    "@babel/preset-react": "^7.10.1",
    "axios": "^0.19.2",
    "babel-loader": "^8.1.0",
    "express": "^4.17.1",
    "nodemon": "^2.0.4",
    "npm-run-all": "^4.1.5",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-helmet": "^6.1.0",
    "react-redux": "^7.2.0",
    "react-router-config": "^5.1.1",
    "react-router-dom": "^5.2.0",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0",
    "serialize-javascript": "^4.0.0",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0",
    "webpack-merge": "^4.2.2",
    "webpack-node-externals": "^1.7.2"
  }
}

2.2 创建node服务器

创建:服务端 src/server/http.js

import express from 'express'


const app = express();

app.listen(3000, () => {
   
  console.log('app is running 3000 port')
})

export default app

服务端入口文件:src/server/index.js

// 服务端入口文件

import React from 'react'
import app from './http'
import Home from '../share/pages/Home'

import {
    renderToString } from 'react-dom/server'


// 接收来自客户端发送的请求
// 当客户端请求地址为:'/',时,服务器端做出的响应。
app.get('/' , (req, res) => {
   
  // renderToString: 返回一个html字符串
  const content = renderToString(<Home/>)
	
  res.send(
    `
      <html>
        <head>react ssr</head>
        <body>
          <div id="root">${
     content}</div>
        </body>
      </html>
    `
  )
})

创建组件: src/share/Home.js

import React from 'react'

function Home () {
   
  return <div>home works </div>
}

export default Home

实现ssr步骤:

  1. 引入要渲染的react组件
  2. 通过renderToString方法将react组件转换为html字符串
  3. 将结果html字符串响应到客户端。

renderToString 方法用于将react组件转换为html字符串,通过react-dom/server导入。

2.3 webpack打包配置

因为当前的代码在运行不起来的。因此需要打包。通过打包之后的代码,启动项目。原因有2 个: 1. node环境不支持 ESModule模块系统,不支持jsx语法。

node版本: v10.16.0

webpack.base.js


// @babel/preset-env:转换高级的js语法,
// @babel/preset-react:转换jsx语法
module.exports = {
   
  mode: "development",
  module: {
   
    rules: [
      {
   
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
   
          loader: "babel-loader",
          options: {
   
            presets: [
              [
                "@babel/preset-env",
                {
   
                  useBuiltIns: "usage"
                }
              ],
              "@babel/preset-react"
            ]
          }
        }
      }
    ]
  }
};

创建服务端webpack配置:webpack.server.js

const path = require('path');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base');

const config = {
   
  target: 'node',
  entry: './src/server/index.js',
  output: {
   
    // path.join拼接路径
    path: path.join(__dirname, 'build'),
    filename: 'bundle.js'
  },
}

module.exports = merge(baseConfig, config);

package.json

//  --exec: 执行命令: \"node build/bundle.js\"
"scripts": {
   
	 // 执行node
    "dev:server-run": "nodemon --watch build --exec \"node build/bundle.js\"",
    // watch 监听文件的变化,当文件内容发生了变化自动去打包
    "dev:server-build": "webpack --config webpack.server.js --watch"
  },

执行:npm run dev:server-build
执行:npm run dev:server-run
打开浏览器:http://localhost:3000/
看到如下效果 react ssr已经实现了:
在这里插入图片描述

2.4 为组件元素附加事件的方式

添加点击按钮事件没有响应,分析问题,我们发现只有html代码,没有js代码
在这里插入图片描述

实现思路:</

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值