阅读 59

React SSR

React SSR简介

客户端渲染(CSR):服务端仅返回JSON数据,DATA和HTML在客户端渲染。

服务端渲染(SSR):服务端返回HTML,DATA和HTML在服务端进行渲染。

客户端渲染存在的问题:

1、首屏等待时间长,用户体验差。

客户端渲染过程: 服务端第一次对客户端响应请求,先只返回一个空的HTML文档,这个即index.html在这个文档中只包含一些css和js的外链。浏览器开始执行Html文档,然后又向服务端请求css和js外链文件。获取js 文件后,又开始向服务端请求页面的数据。等数据回来,然后等待js 把数据拼接好,然后此时时客户界面才会从空白到出现内容。

服务端渲染过程: 服务端先返回拼接好的html和数据,用户可以看到页面内容,虽然是静态的页面。接着发送js 请求,再解析js 的内容,最终,页面拥有动态的效果。且返回的是一个完整的html 的页面,利于搜索引擎的实现。

2、页面结构为空,不利于seo。

React SSR 的核心在于同构,让代码复用,实现客户端和服务端最大程度的代码复用。

初步渲染

1、引入要渲染的React组件 2、通过renderToString方法将React的组件转换为HTML字符串 3、将结果HTML字符串发送到客户端

webpack 的打包配置: Node环境不支持ESModule模块系统,不支持JSX 的语法。

为元素添加事件

开始只会返回html结构,而没有任何js代码,在客户端进第二次渲染,为组件元素添加事件。hydrate能够实现客户端二次渲染,复用原本已经存在和Dom节点,减少重新生成节点和删除原来节点的开销,通过react-dom 导入hydrate。

思路:1、在客户端进行使用hydrate进行二次渲染。

ReactDom.hydrate(<Home/>,document.getElementById("root"))
复制代码

2、添加babel配置。

const path = require('path')
module.exports = {
    mode:"development",
    entry:"./src/client/index.js",
    output:{
        path:path.join(__dirname,"public"),
        filename:"bundle.js"
    },
    module:{
        rules:[
            {
                test:/\.js$/,
                exclude:/node_modules/,
                use:{
                    loader:"babel-loader",
                    options:{
                        presets:["@babel/preset-env","@babel/preset-react"]
                    }
                }
            }
        ]
    }
}
复制代码

3、在服务端返回的Html的结构中,添加

<html>
            <head>
                <title> React ssr </title>
            </head>
            <body>
                <div id ="root"> ${content} </div>
                <script src = "bundle.js">  </script>
            </body>
        </html>
复制代码

4、服务端实现静态资源访问。

app.use(express.static("public"));
复制代码

一些优化: 1、合并webpack:webpack-merge 2、合并项目启动命令:npm-run-all 3、服务器端大包体积优化:webpack-node-externals 4、将启动服务器的代码和渲染组件的代码进行区分

路由实现

服务端路由实现:

1、设置统一的路由规则,导出数组对象的路由形式。 2、使用renderRoute 将数组对象转变组件形式。 3、使用StaticRouter进行路由匹配

部分代码

import { renderToString }  from 'react-dom/server'
import { renderRoutes }  from "react-router-config"
import { StaticRouter } from "react-router-dom"
import routes from '../share/routes'


export default req => {
    const content = renderToString(<StaticRouter location= {req.path}> {renderRoutes(routes)}</StaticRouter>)
    return `
    <html>
        <head>
            <title> React ssr </title>
        </head>
        <body>
            <div id ="root"> ${content} </div>
            <script src = "bundle.js">  </script>
        </body>
    </html>

`
}

复制代码

客户端路由实现:

import React from "react"

import ReactDom from "react-dom"

import { BrowserRouter } from "react-router-dom"

import { renderRoutes } from 'react-router-config'

import routes from '../share/routes'

ReactDom.hydrate(<BrowserRouter>{renderRoutes(routes)}</BrowserRouter>,document.getElementById("root"))
复制代码
文章分类
前端
文章标签