Vue框架使用SSR

Vue 同构渲染

Vue.js 是一个构建客户端应用的框架,组件的代码会在浏览器中运行,然后向页面输出 DOM 元素,也就是我们最常用的方式,即 客户端渲染(client-side rendering,CSR) . 实际上 Vue.js 还可以在 Node.js 环境中运行,即可将相同组件渲染成相应的字符串,并发送给浏览器进行渲染,这就是 服务端渲染(server-side rendering,SSR) . Vue.js 作为现代前端框架,除了能够分别支持 CSR 或 SSR 渲染之外,还能够同时支持 CSR 和 SSR,这就是所谓的 同构渲染(isomorphic rendering).

客户端渲染 CSR

  • CSR 优点
    • 对于 SPA 应用,跳转之前没有卡断和刷新,体验会比较好。基于前端路由的方式不会导致真正的页面跳转,带来了使用过程中的流畅度。
    • 占用的服务端压力较少。CRS 的渲染是交给客户端额,服务端不用关注页面的渲染和计算过程,只需要关注数据。
  • CSR 缺陷
    • 白屏时间会很长。因为 CSR 渲染需要.js 的支持,js 如果很大,请求和执行都很耗时间,如果用户网络环境较差,就会导致很长的白屏时间。
    • 对 SEO 的支持不友好。因为白屏时间较长,也会导致在一段时间内没有重要的内容交给搜索引擎进行分类、打标等,并且搜索引擎并不会等待页面渲染完成,因此对 SEO 优化很不友好。

服务端渲染 SSR

渲染流程

  • 搭建 node 服务
    • Node.js 服务器是长期运行的进程,当代码第一次被导入进程时,它会被执行一次然后保留在内存里
    • 如果只创建了一个 Vue 的单例对象,它将被每次发来的请求共享,这是不符合实际需求的,因此我们需要为每个请求重新生成一个 vue 实例,避免相互影响
  • SSR 优势
    • 首屏渲染速度快,用户体验好,不存在白屏时间过长的问题
    • SEO 友好,搜索引擎可以爬取到完整的 html 内容,也不存在异步的接口调用
  • SSR 劣势
    • 需要保障服务端和客户端的代码一致性,否则会出现不一致的情况。(比如:路由,vuex 等等)
    • 保证开发一致性:浏览器特有的代码只能在特定的生命周期钩子中使用,一些外部库在服务端渲染时可能需要特殊处理
    • 提供稳定的能够支持高并发的服务器环境,需要考虑服务器的负载,内存,CPU,带宽等
    • 更多的服务端荷载,需要考虑服务端渲染的优化,比如:缓存,压缩,静态资源分离等
      • 更多的服务端负载:在 Node.js 中渲染一个完整的应用,需要更密集的 CPU 运算,如果访问的流量很高,我们需要考虑负载均衡、合理的缓存策略、容错机制
  • SSR 和 预渲染
    • 预渲染可以在构建的时为指定的路由生成静态的 HTML 文件,预渲染需要和打包构建工具(webpack、Vite......)配合,我们使用静态工具打包出 HTML 后,发布到 CDN 上即可,用户访问时直接访问的是静态的 HTML 文件,无需经过服务器渲染,所以首屏加载速度非常快,但是预渲染无法处理异步数据,所以预渲染一般用于静态的页面,比如:博客,文档等

同构渲染(isomorphic rendering)

壹. 同构流程

  • 服务端渲染应用快照 (静态 HTML 页面)
    • 生成快照的同时,还会当成当前数据状态的初始数据,给客户端做初始化处理
    • 应用快照不具备交互能力,即定义好的事件不会注册到 DOM 上,需要在客户端激活
  • 客户端激活
    • 把当前页面已经渲染的 DOM 元素和 Vue.js 渲染的虚拟 DOM 建立联系
    • 由于真实 DOM 和虚拟 DOM 都是树形结构,并且节点之间存在相互关系的,激活就可以通过递归在 DOM 和虚拟 DOM 之间建立联系。即 vnode.el = el,并且保证是从容器元素的第一个子节点开始,即 el.firstChild
    • 为页面中 DOM 元素添加事件绑定,使页面具备交互能力
    • Vue.js 从 HTML 中提取服务端序列化后发送过来的数据,用于初始化整个 Vue.js 的应用

同构渲染就是一套代码,既可以在服务端执行,也可以在客户端执行,从而在服务端生成 html,在客户端执行 js,从而实现首屏渲染。

importmap

<script> 元素的 type 属性的 importmap 值表示元素的主体包含一个导入映射。

贰. 同构案例

  1. 服务器端渲染 HTML 字符串
  2. 通过服务器发送 HTML 字符串
  3. 激活客户端渲染

叁. 实现脱水(Dehydrate)和注水(Hydrate)

  • 实现服务器端脱水
    • 服务器端获取到数据后,把数据跟随 HTML 一起传给客户端的过程
    • 脱水:把 Vue.js 的状态数据序列化成字符串,发送给客户端
  • 实现客户端注水
    • 客户端拿到 HTML 和数据,利用这个数据来初始化组件
    • 注水:客户端接收到脱水后的数据,把数据注入到 Vue.js 中,从而实现客户端的激活

肆. 同构渲染要点

  • 避免状态单例,也就是避免将对象或变量创建在全局作用域中,否则它会在所有请求之间共享,在不同请求中造成状态污染,导致服务端和客户端状态不一致
  • 避免访问特定平台的 API,比如:window、document、localStorage 等,这些 API 只能在浏览器环境中使用,在服务端渲染时会导致错误
  • node 端和浏览器端 API 不适配,推荐将操作 DOM 或者访问 window 等浏览器行为,写在 onMounted 生命周期中,这样就可以避免在 node 端访问浏览器 API 导致报错
js 复制代码
// 使用环境变量
// Vite 内
const isSSR = import.meta.env.SSR;
if (isSSR) {
	// 服务端渲染,仅在服务端执行的逻辑
} else {
	// 客户端渲染,仅在客户端执行的逻辑
}
  • 避免在服务端生命周期内执行全局副作用代码,比如 setInterval。因为服务端不会执行 destroy 的销毁 hook,会导致服务器内存溢出

伍. 创建实际生产中的同构应用

  • 集成前端工具链
  • 集成前端路由
    • 使用 createMemoryHistory 创建内存路由
    • 在服务端获取到用户请求的路径后,把路径传入 router.push 函数,使用 router.isReady() await 这个函数后,再渲染整个应用
  • 集成全局状态管理库
    • 需要确定你使用的状态管理工具支持 SSR
  • 处理#app节点之外的元素
  • 处理预加载资源

陆. 服务器端优化

  1. 服务器端测试
  • 我们可以通过 apach bench, jmeter 等
  • abs -n 1000 -c 100 http://localhost:3000/ ,表示以 100 并发的形式发送了 1000 个请求到 localhost: 3000
  • 我们可以接入 nodejs 的监控告警,保证服务稳定性
  1. 多进程优化
js 复制代码
const cluster = require("cluster");
// cpu总数
const numCPUs = require("os").cpus().length;
module.exports = (task) => {
	if (cluster.isMaster) {
		for (let i = 0; i < numCPUS / 2; i++) {
			const worker = cluster.fork();
		}
	} else {
		task();
	}
};
  1. 内存溢出处理
  • 我们可以通过 process 判断当前子进程用掉的内存,当占用内存大于阈值的时候,就关掉这个子进程,防止内存泄漏
js 复制代码
const timer = setInterVal(() => {
	const mem = process.memoryUsage();
	if (mem.rss > 300 * 1024 * 1024) {
		cleaterVal(timer);
		process.exit(1);
	}
}, 5000);
  1. 处理未捕获异常
js 复制代码
process.on("oncaughtException", (err) => {
	// 需要对错误进行日志上报,写入日志,比如sentry
	process.exit(1);
});
  1. 心跳包检测
  • 防止子进程卡死
    • 主进程通过 worker.send 给子进程发送消息
    • 子进程通过 process.on('messgae', () => {})订阅主进程发送的消息,然后通过 process.send 返回给主进程信息
    • 主进程通过 worker.on('message', () => {})订阅子进程发送的信息,如果累计一定次数没有收到子进程返回的信息,则关闭子进程
  1. 子进程自动重建
js 复制代码
cluster.on("exit", () => {
	// 创建新的子进程
	setTimeout(() => {
		createWorker();
	});
});

使用 PM2 部署我们的 SSR 应用 然后使用同构应用框架进行开发

相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax