CSR和SSR

  客户端渲染CSR

    服务器向浏览器发送空的HTML文档-> 然后浏览器下载JS文件 -> 浏览器执行React代码->页面渲染完毕

  服务器端渲染SSR

    服务器直接发送HTML文档

  比较:

    我们可以看出SSR架构下页面非常快,只需要下载HTML,也就是说首屏加载非常快

    SEO 百度爬虫是认识HTML,也就是说只有SSR在百度会有一个好的排名

配置服务器webpack

首先我们在src目录下创建index.js 简单的服务器代码

const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.send(
    `
      <html>
        <head>
          <title>React SSR</title>
        </head> 
        <body>
          <h1>React SSR</h1>
        </body>
      </html>
    `
  )
})
var server = app.listen(3000)

修改package.json

"start": "node ./src/index.js"

npm run start 运行

我们能在3000页面看到React SSR

现在我们通过wepack打包服务器代码 

  我们先安装webpack  webpack-cli  babel-loader  babel-core babel-preset-env babel-preset-react babel-preset-stage-0  webpack-node-externals

然后在跟目录创建webpack.config.server.js配置如下

const path = require('path')
const nodeExternals = require('webpack-node-externals')

module.exports = {
  target:'node',
  mode:'development',
  entry:'./src/index.js',
  output:{
    filename:'bundle.js',
    path: path.resolve(__dirname, 'build')
  },
  externals:[nodeExternals()],
  module:{
    rules:[
      {
        test:/\.js?$/,
        loader:'babel-loader',
        exclude:/node_modules/,
        options: {
          presets:['react','stage-0',['env', {
            targets: {
              browsers: ['last 2 versions']
            }
          }]]
        }
      }
    ]
  }
}

我们把src/index.js打包到build/bundle.js下然后修改package.json

"start": "node ./build/bundle.js"

"build":"webpack --config webpack.server.js"
我们再次npm run build    npm run start
我们能在3000端口看到React SSR , 至此我们完成了服务器端的webpack配置
服务器组件渲染
现在我们在在src/pages/home/index.js创建一个普通的React Component
然后在src/index.js引入HomeComponent
我们现在需要安装react-dom 然后我们修改src/index.js
我们可以看出我们使用react-dom中的 renderToString 实现服务器渲染组件
var express = require('express')
import React from 'react'
import {renderToString} from 'react-dom/server'
import Home from './pages/home'

var app = express()

app.get('/', function (req, res) {
  res.send(
      `<html>
            <head>
                <title>hello</title>
            </head>
            <body>
                <h1>first lesson</h1>
        <p>hello world</p>
        ${renderToString(<Home/>)}
            </body>
      </html>`
  )
})
var server = app.listen(3000)

接着build  & start  3000端口页面会出现Home组件内容,查看浏览器源代码,我们可以看到Home组件源代码

到此我们已经实现了基本的React在服务器端渲染

优势:react的服务器端渲染也是使用React虚拟DOM,加快了首屏加载速度,SEO

劣势:服务端端渲染react代码在服务器上执行,消耗服务器性能

同构技术

首先我们先修改HomeComponent代码,加个Button.click事件,然后在浏览器发现click事件不触发

因为renderToString方法不会把事件渲染出来

我们可以让react在服务器端执行一次,然后在客户端执行一次,这就是同构的概念

首先我们在根目录下创建public/index.js 文件。里面一句console.log代码

接下来我们使用在src/index.js目录下添加如下代码,

app.use(express.static('public'))

页面引用<script src="/index.js"></script>

我们再次打包编译就能看到控制台打印一句话

我们到此浏览器可以执行一段JS文件

具体服务器会到publick找到js文件 浏览器根据script找到js文件,于是浏览器就能执行js文件

我们现在能执行js文件了,那么我们开始让React代码在浏览器运行

创建src/client/index.js 代码如下

import React from 'react'
import ReactDOM from 'react-dom';

import Home from '../src/pages/home'

ReactDOM.render(<Home/>, document.getElementById('root'))

接下来在跟目录添加webpack.client.js

const path = require('path')

module.exports = {
  mode:'development',
  entry:'./src/client/index.js',
  output:{
    filename:'index.js',
    path: path.resolve(__dirname, 'public')
  },
  module:{
    rules:[
      {
        test:/\.js|jsx?$/,
        loader:'babel-loader',
        exclude:/node_modules/,
        options: {
          presets:['react','stage-0',['env', {
            targets: {
              browsers: ['last 2 versions']
            }
          }]]
        }
      }
    ]
  }
}

 打包代码执行

这时候浏览器会warning因为react在服务器渲染一次在客户端渲染一次也就是同构的话。我们可以修改client/index.js

ReactDOM.hydrate(<Home/>, document.getElementById('root'))

到此我们可以在实现同构了,通过打包一次服务器端代码一个客户端代码,然后服务器通过script引入 实现了Button.click的点击事件了

代码优化

首先我们修改下代码结构,我们在之前创建的index.js文件下是在src目录下,我们优化下目录结构把index.js文件移到src/server/index.js文件,下具体文件格式如下

优化webpack配置文件

安装  webpack-merge

跟目录创建webpack.base.js代码提取webpack.client和webpack.server公共代码具体代码

webpack.base.js

module.exports = {
  module:{
    rules:[
      {
        test:/\.js|jsx?$/,
        loader:'babel-loader',
        exclude:/node_modules/,
        options: {
          presets:['react','stage-0',['env', {
            targets: {
              browsers: ['last 2 versions']
            }
          }]]
        }
      }
    ]
  }
}

webpack.client.js

const path = require('path')
const merge = require('webpack-merge')
const config = require('./webpack.base')
const clientConfig = {
  mode:'development',
  entry:'./src/client/index.js',
  output:{
    filename:'index.js',
    path: path.resolve(__dirname, 'public')
  }
}
module.exports = merge(config, clientConfig)

webpack.server.js

const path = require('path')
const nodeExternals = require('webpack-node-externals')
const merge = require('webpack-merge')
const config = require('./webpack.base') 
const serverConfig = {
  target:'node',
  mode:'development',
  entry:'./src/server/index.js',
  output:{
    filename:'bundle.js',
    path: path.resolve(__dirname, 'build')
  },
  externals:[nodeExternals()]
}

module.exports = merge(config, serverConfig)

 此次我们可以对服务器端渲染有了新的了解

   服务器端运行React代码渲染HTML->发送HTML给浏览器->浏览器接受HTML展示页面内容->浏览器加载JS文件->JS文件在浏览器重新执行->JS中的React接管页面的操作

 

  

  

 

 

  

 

 

 

  

      

    

  

  

posted on 2018-12-10 05:23  苏荷酒吧  阅读(156)  评论(0)    收藏  举报