服务端渲染(ssr)和客户端渲染(csr)
- 服务端渲染:在服务端把你想要渲染的内容直接拼接成html字符串,然后返回给客户端渲染。
- 客户端渲染:在浏览器端加载解析html完成之后,再去执行js代码,由js代码把你想要渲染的内容插入到页面中。
服务端渲染和客户端渲染相比较,服务端渲染有利有弊,优点有如下:
(1)加快了首屏渲染的速度
(2)有利于seo优化,提高在搜索引擎中的排名。
缺点有如下:
(1)对开发者的要求更高,要了解服务端的知识。
(2)增加了开发运维的成本,服务器资源开销比较大。
所以,我们在开发中,到底要使用哪一种渲染方式,要根据具体的业务场景来订,不到万不得已,不要使用服务端渲染。
服务端渲染基本流程
- 初始化npm包,安装express或者koa(这里我用koa为例),搭建本地服务器。
然后编写服务器单独入口文件server/index.js,代码如下:
import Koa from "koa";
import fs from "fs";
import path from "path";
import React from "react";
import { renderToString } from "react-dom/server";
import Home from "../src/page/home/index.jsx";
const app = new Koa();
const rootPath = process.cwd();
// 模板html的路径
const templatePath = path.join(rootPath, "public/index.html");
// 读取模板html内容
const template = fs.readFileSync(templatePath).toString();
app.use(async (ctx) => {
const ssrContent = renderToString(<Home />);
// 把模板html的内容替换成组件内容
const html = template.replace("<!-- ssr slot -->", ssrContent);
// 返回给浏览器
ctx.body = html;
});
app.listen(3000);
Home组件代码如下:
import React from "react";
const Home = () => {
const showInfo = () => alert('有用户点击');
return <div className="home" onClick={showInfo}>Home</div>
}
export default Home;
模板html内容,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- ssr slot -->
</body>
</html>
现在基本服务器搭建完成。
- 服务端webpack配置,对服务端的react代码进行打包。安装下图插件:
在根目录下创建webpack.server.js文件,配置如下:
const path = require("path");
const nodeExternal = require("webpack-node-externals");
module.exports = {
mode: "development",
target: "node",
entry: path.resolve(__dirname, "./server/index.js"),
output: {
path: path.resolve(__dirname, "./server-build"), // 输出的路径
filename: "server-bundle.js", // 打包后文件
},
externals: [nodeExternal()],
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: /node_modules/,
},
],
},
};
babel配置文件.babelrc如下:
{
"presets": [
"@babel/preset-react",// react 转码规则
"@babel/preset-env" // es2015规则
],
"plugins":[
"@babel/plugin-transform-runtime"
]
}
package.json的script如下:
现在命令行运行npm run build:server
完成之后,然后运行node ./server-build/server-build.js
即可访问(localhost:3000)。但是,现在我们给组件加上点击事件,在浏览器端并不会做出响应,因为服务器端只负责前期试图呈现渲染的工作,并不会负责与用户的交互等操作,这些操作还是等交给浏览器的js来负责,所以现在我们需要打包编译客户端react代码并且引入(这个过程叫同构
)。
- 编写客户端react代码,新建client/index.js,如下:
import React from "react";
import ReactDom from "react-dom";
import Home from "../src/page/home/index.jsx";
ReactDom.hydrate(<Home />, document.getElementById("root"));
- 客户端webpack配置,对客户端react代码进行打包,所安装插件和服务端一样。在根目录下新建webpack.client.js文件,配置如下:
const path = require("path");
module.exports = {
mode: "development",
entry: path.resolve(__dirname, "./client/index.js"), //指定入口文件,程序从这里开始编译,__dirname当前所在目录, ../表示上一级目录, ./同级目录
output: {
path: path.resolve(__dirname, "./client-build"), // 输出的路径
filename: "client-bundle.js", // 打包后文件
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: /node_modules/,
},
],
},
};
package.json的script如下:
运行npm run build:client
打包完成之后,模板html引入客户端打包的代码并且服务器端配置静态资源访问即可。代码如下:
// 模板html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
+ <div id="root"><!-- ssr slot --></div>
+ <script src="/client-bundle.js"></script>
</body>
</html>
///////////////////////////////////////////////
// 服务器端的代码
import Koa from "koa";
import fs from "fs";
import KoaStatic from "koa-static";
import path from "path";
import React from "react";
import { renderToString } from "react-dom/server";
import Home from "../src/page/home/index.jsx";
const app = new Koa();
const rootPath = process.cwd();
+ // 静态文件路径
+ const staticPath1 = path.join(rootPath, "client-build");
// 模板html的路径
const templatePath = path.join(rootPath, "public/index.html");
// 读取模板html内容
const template = fs.readFileSync(templatePath).toString();
+ // 访问静态文件
+ app.use(KoaStatic(staticPath1));
app.use(async (ctx) => {
const ssrContent = renderToString(<Home />);
// 把模板html的内容替换成组件内容
const html = template.replace("<!-- ssr slot -->", ssrContent);
console.log(html);
// 返回给浏览器
ctx.body = html;
});
app.listen(3000);
现阶段如果服务端代码或者客户端代码有更改之后,需要我们手动去执行命令才能看到最新的结果。下面对webpack进行配置完成自动打包。首先安装nodemon
、npm-run-all
插件,然后配置package.json的script命令即可,代码如下:
现在我们只需要运行npm run dev
即可,当我们的文件有更新时,刷新浏览器即可得到最新结果。
后续会逐步加入react-router-dom和redux等,关注github仓库地址
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!