React 下的同構(gòu)渲染
嗨,我是你穩(wěn)定更新、持續(xù)輸出的勾勾。

昨天我們討論了如何手動實現(xiàn)一個自己的服務端渲染 Reac SSR,各位小伙伴有沒有 get 到一些知識。
React 的客戶端渲染 CSR ,大家都比較熟悉,這里我就言簡意賅的介紹下。
# Client 下的 webpack 配置
在當前項目的目錄下創(chuàng)建一個?webpack.client.js?的文件,它是客戶端打包的處理文件,內(nèi)容如下:
//webpack.client.jsconst path = require("path")module.exports = {mode:"none",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']}}}]}}
webpack.client.js 這個配置文件的內(nèi)容跟 webpack.server.js 文件相比,在 entry 的屬性值上有所不同。
webpack.client.js 的入口文件是 client 下的 index.js 文件,這個 index.js 文件也是咱們常寫的,但是需要注意的是它里面的書寫內(nèi)容有所改動。
//client/index.jsimport React from "react"import ReactDOM from "react-dom"import Home from "../common/pages/home"ReactDOM.hydrate(<Home/>,document.getElementById("root"))
這里我們沒有使用 ReactDOM.render() 來渲染,而是換成了 ReactDOM.hydrate()。
至于 hydrate 的學習大家可以參考 https://react.docschina.org/docs/react-dom.html#hydrate?
它是對服務端渲染后的結(jié)果的二次渲染,因為服務端渲染后的結(jié)果是一個純靜態(tài)頁面。
如果是和用戶的一些操作行為相關的 JavaScript 代碼就需要 hydrate 的二次渲染,它會把 JavaScript 代碼進行加載執(zhí)行。
還有一個不同的地方就是打包后存放的位置不同。
總結(jié)一下兩者的處理結(jié)果:
服務端渲染,我們將對應在 server 下的 index.js 文件打包到 dist 目錄,生成文件叫 build.js
客戶端渲染,我們將對應在 client 下的 index.js 文件打包到 public 目錄,生成文件叫 bundle.js
# 配置指令
配置文件寫好之后,我們就需要配置客戶端打包的指令。打開 package.json 文件,在 scripts 中配置客戶端打包指令:
//package.json"scripts": {"dev:server-build": "npx webpack --config webpack.server.js --watch","dev:client-build": "npx webpack --config webpack.client.js --watch""dev:server-run": "nodemon --watch dist --exec \"node dist/build.js\""},
這里我們可以看到,我們加了 --watch 參數(shù)(功能可以參考 wenpack 配置)。配置打包后,我們也配置了 nodemon 對 dist 目錄的監(jiān)控和對 dist/build.js 的執(zhí)行。
# 轉(zhuǎn)折重點
現(xiàn)在我們把客戶端和服務端的打包都配置成功,緊接著我們需要思考:
服務端打包后生成了靜態(tài)頁面,渲染了出來,那么客戶端在二次渲染的時候怎么執(zhí)行 public/bundle.js 文件?
需要我們分兩步解決:
1、我們需要在服務端 server 下的文件 index.js 添加 script 標簽,引入客戶端打包后的 bundle.js
//server/index.jsimport app from "./http"import React from "react"import Home from "../common/pages/home";import { renderToString } from "react-dom/server"app.get("/",(req,res)=>{const content = renderToString() res.send(`${content}`)})
2、配置靜態(tài)文件?
在 server/http.js 中配置靜態(tài)資源文件
//server/http.js// import express from "express"const express = require("express")const app = express()app.use(express.static("public"))app.listen(3000,() => {console.log("sdfdsfsf")})export default app;
到此,一個完整的服務端渲染和客戶端渲染同時存在的小項目就搭建成功了。對于這種兩者兼具的渲染方式,我們把它稱為同構(gòu)渲染。
明天,我們來聊聊同構(gòu)渲染常見的優(yōu)化手段,下期見~
推薦閱讀:
前端人因為 Vue3 的 Ref-sugar 提案打起來了!
點點“贊”和“在看”,保護頭發(fā),減少bug。
