手动实现一个自己的 React 服务端渲染

544 阅读2分钟

为什么要有服务端渲染?

框架开发是当前炙手可热的流行趋势,SPA 这种模式也被越来越多的人认可,但是随着研究的深入,一些问题就慢慢凸显出来了。

最重要的两点,一是首页需要等待;第二,不利于 SEO 。

为了解决这些问题,框架也推出了自己的解决方案——Server Side Rendering 服务端渲染

本篇文章就以 React 为例,聊聊如何在 react 环境下手动实现一个 SSR ?

真枪实弹的第一步

首先,在项目下创建一个文件夹 src,在里面放置三个文件夹 client (客户端代码),common(共同的代码),server(服务端代码)。

这里 server 文件夹是我们关注的重点。在这个 server 文件夹下,我们需要创建一个 http.js 文件,内容如下,目的是启动一个服务。

//http.js
const express = require("express")
const app = express()
app.listen(3000,function(){console.log("server is runing")})
export default app;

同时再添加一个 index.js 文件,内容如下。拆分两个文件的目的是为了保证服务代码和业务代码分离

import app from "./http"
import React from "react"
import {renderToString} from "react-dom/server" //将组件转成字符串格式
import Home from "../common/Home"
app.get("/",function(req,res){
    const string = renderToString(<Home></Home>)   //
    res.send(`  //这是一个字符串模板哦
        <html>
            <head>
                <title>react-ssr</title>
            </head>
            <body>
                <div id="root">${string}</div>
            </body>
        </html>
    `)
})

这里面解释几个点:

  • renderToString 这个方法是专门将组件转成字符串格式的。

  • Home 是在 common 文件夹下创建的一个组件 Home.js,内容如下:

    import React from "react" function Home(){ return (

    hello world
    ) } export default Home;

注意:

如果我们直接使用 Node 来启动服务,会报语法性错误,错误原因:

  • Node 下不支持 ESModule 语法

  • Node 下不支持 React 中的 JSX 语法

所以我们需要引入 webpack 进行打包,然后再启动服务。

# Webpack 配置

我们在项目下创建一个 webpack.server.js,内容如下:

const path = require("path")
module.exports = {
    mode:"none",
    target:"node",
    entry:"./src/server/index.js",
    output:{
        path:path.join(__dirname,"dist"),
        filename:"build.js"
    },
    module:{
        rules:[
            {
                test:/\.js$/,
                exclude:/node_modules/,
                use:{
                    loader:"babel-loader",
                    options:{
                        presets:['@babel/preset-env','@babel/preset-react']
                    }
                }
            }
        ]
    }
}

注意,我们需要安装 webpack webpack-cli。

对于 js 文件,我们需要使用 babel-loader,把它交给 babel 处理,所以要下载

Babel-loader @babel/core @babel/preset-env @babel/preset-react。

接下来配置 options,添加预设 presets。

# Webpack 打包

配置文件完成之后,我们需要打包,打包指令就是 npx webpack -- config webpack.server.js。对于这种打包指令很麻烦,我们需要在 package.json 中配置一个自己用的顺手的指令,修改如下:

//package.json
{
  "name": "react-ssr",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "dev:server-build":"npx webpack --config webpack.server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.12.9",
    "@babel/preset-env": "^7.12.7",
    "@babel/preset-react": "^7.12.7",
    "babel-loader": "^8.2.2",
    "express": "^4.17.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "webpack": "^5.9.0",
    "webpack-cli": "^4.2.0"
  }
}

当 npm run dev 一打包,就会出现一个 dist 文件夹,里面有个 build.js 文件。

Node 启动服务

最后,我们在终端使用 node dist/build.js 就可以直接启动这个文件。在网页中输入对应的 url,就会显示一个我们手动实现的服务端渲染案例,但这个页面是一个纯静态的页面。

至此,实现一个 React 的 SSR 就算完成了~