当前位置: 首页 > news >正文

vue3优化SSR在哪

SSR 的优化是一个系统性工程,涉及代码层面、构建层面、服务器层面、网络层面等多个维度。

1. SSR 本身的性能瓶颈在哪?

在讲优化之前,先搞清楚 SSR 为什么慢:

普通 CSR: 浏览器请求 → 返回空白 HTML → 下载 JS → 执行 → 渲染 ↓ 瓶颈在:网络带宽(JS 体积) SSR: 浏览器请求 → 服务器运行 Vue → 生成 HTML → 返回 ↓ 瓶颈在:服务器 CPU(每次请求都要渲染)

核心问题:SSR 把"渲染"从客户端搬到了服务器,服务器的 CPU 成了新的瓶颈。

2. 代码层面的优化

优化一:组件级别的缓存(缓存不常变的内容)

<!-- ❌ 不缓存:每次请求都重新渲染 --> <template> <div> <Header /> <!-- 每个用户看到的都一样 --> <ProductList /> <!-- 变化频繁 --> <Footer /> <!-- 每个用户看到的都一样 --> </div> </template>
<!-- ✅ 缓存静态部分 --> <template> <div> <!-- 用 v-once 缓存静态内容 --> <Header v-once /> <ProductList /> <Footer v-once /> </div> </template>

更高级的做法:使用@vue/server-rendererrenderToNodeStream+ 组件缓存:

// server.js import LRU from 'lru-cache' import { createRenderer } from '@vue/server-renderer' // 创建组件缓存(缓存 1000 个组件,有效期 1 分钟) const cache = new LRU({ max: 1000, maxAge: 1000 * 60 }) const renderer = createRenderer({ cache }) // 在组件中启用缓存 // ProductList.vue export default { name: 'ProductList', serverCacheKey: () => { // 根据数据生成缓存 key return `product-list-${this.category}-${this.page}` } }

优化二:避免在组件中写"重"逻辑

// ❌ 错误:在 setup 中做大量计算(服务端每次请求都执行) const expensiveData = computed(() => { return hugeArray .filter(x => x > 0) .map(x => x * 2) .sort((a, b) => a - b) // ... 大量计算 }) // ✅ 正确:把计算挪到客户端 const expensiveData = ref(null) onMounted(() => { // 只在浏览器执行 expensiveData.value = hugeArray .filter(x => x > 0) .map(x => x * 2) .sort((a, b) => a - b) })

优化三:使用v-memo(Vue 3.2+)缓存 DOM

<template> <!-- v-memo 会缓存这个 DOM 片段,依赖的值不变就不重新渲染 --> <div v-memo="[product.id, product.price]"> <h3>{{ product.name }}</h3> <p>价格:{{ product.price }}</p> <p>库存:{{ product.stock }}</p> </div> </template>

3. 构建层面的优化

优化一:代码分割(按需加载)

// router/index.js const routes = [ { path: '/', component: Home // 立即加载 }, { path: '/product/:id', // ✅ 懒加载:只有访问时才加载这个组件 component: () => import('@/views/Product.vue') }, { path: '/checkout', component: () => import('@/views/Checkout.vue') } ]

优化二:只打包必要的代码

// vite.config.js(Vite 项目) export default { build: { rollupOptions: { output: { // 手动分割 chunk manualChunks: { vendor: ['vue', 'vue-router', 'pinia'], // 第三方库单独打包 ui: ['element-plus'] // UI 库单独打包 } } } } }

优化三:启用 gzip 压缩

// vite.config.js import compression from 'vite-plugin-compression' export default { plugins: [ compression({ algorithm: 'gzip', threshold: 10240 // 10KB 以上的文件才压缩 }) ] }

4. 服务器层面的优化

优化一:启用缓存(最重要的优化!)

// server.js import express from 'express' import LRU from 'lru-cache' const app = express() const cache = new LRU({ max: 100, // 最多缓存 100 个页面 maxAge: 1000 * 60 // 缓存 1 分钟 }) app.get('*', async (req, res) => { // 1. 检查缓存 const cacheKey = req.url const cached = cache.get(cacheKey) if (cached) { // ✅ 命中缓存:直接返回,不渲染 return res.send(cached) } // 2. 未命中:渲染并缓存 const html = await renderSSR(req) cache.set(cacheKey, html) res.send(html) })

优化二:使用流式渲染(Streaming)

// ❌ 普通渲染:等全部渲染完才返回 const html = await renderToString(app) res.send(html) // ✅ 流式渲染:边渲染边发送(用户更快看到内容) import { renderToNodeStream } from '@vue/server-renderer' const stream = renderToNodeStream(app) stream.pipe(res) // 浏览器会逐步渲染

优化三:集群模式(利用多核 CPU)

// server.js import cluster from 'cluster' import os from 'os' if (cluster.isMaster) { // 主进程:fork 多个工作进程 const numCPUs = os.cpus().length for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // 工作进程:运行 SSR 服务器 const app = express() app.get('*', async (req, res) => { // SSR 逻辑... }) app.listen(3000) }

优化四:使用 CDN 缓存静态资源

# nginx.conf location /assets/ { # 静态资源设置长期缓存 expires 1y; add_header Cache-Control "public, immutable"; } location / { # HTML 不缓存或短缓存 expires 1m; add_header Cache-Control "public, max-age=60"; }

5. 网络层面的优化

优化一:HTTP/2 Server Push(主动推送)

// server.js import spdy from 'spdy' // HTTP/2 服务器 const server = spdy.createServer({ key: fs.readFileSync('server.key'), cert: fs.readFileSync('server.cert') }, app) server.on('stream', (stream) => { // 主动推送关键 CSS/JS stream.pushStream({ path: '/assets/app.css' }, (err, pushStream) => { pushStream.respond({ 'content-type': 'text/css' }) pushStream.end(fs.readFileSync('dist/assets/app.css')) }) })

优化二:资源预加载

<!-- 在 HTML 模板中添加预加载 --> <head> <!-- 预加载关键资源 --> <link rel="preload" href="/assets/app.js" as="script"> <link rel="preload" href="/assets/app.css" as="style"> <!-- DNS 预解析 --> <link rel="dns-prefetch" href="//api.example.com"> <!-- 预连接 --> <link rel="preconnect" href="https://api.example.com"> </head>

6. 数据层面的优化

优化一:减少数据请求

// ❌ 错误:每个组件都单独请求 // Header.vue const user = await fetch('/api/user') // ProductList.vue const products = await fetch('/api/products') // Footer.vue const config = await fetch('/api/config') // ✅ 正确:在服务端一次性请求所有数据 export async function getServerData() { const [user, products, config] = await Promise.all([ fetch('/api/user'), fetch('/api/products'), fetch('/api/config') ]) return { user, products, config } } // 然后通过 Pinia 或 props 传递给所有组件

优化二:只传输必要的数据

// ❌ 错误:返回全部数据 // 包含 createdAt, updatedAt, 描述... const product = await db.product.findByPk(id) // ✅ 正确:只返回需要的字段 const product = await db.product.findByPk(id, { attributes: ['id', 'name', 'price', 'image'] // 只选需要的 })

7. Nuxt 3 自带优化(开箱即用)

如果你用 Nuxt 3,很多优化已经帮你做了:

优化项Nuxt 3 是否自动处理
代码分割✅ 自动
路由懒加载✅ 自动
静态资源压缩✅ 自动
组件缓存⚠️ 需配置serverCacheKey
流式渲染✅ 自动(renderToNodeStream
预加载✅ 自动生成preload标签
数据去重useFetch自动去重
// Nuxt 3 中开启更多优化 // nuxt.config.ts export default defineNuxtConfig({ nitro: { // 使用更快的渲染引擎 preset: 'node-server', // 启用缓存 cache: { swr: true, maxAge: 60 } }, // 开启实验性功能 experimental: { payloadExtraction: true, // 提取 payload,减少重复渲染 renderJsonPayloads: true // 使用 JSON 格式传输数据 } })

8. 优化效果对比

优化手段预期提升实施难度
页面缓存(LRU)⬆️ 响应时间减少 70-90%⭐ 简单
流式渲染⬆️ 首屏时间减少 30-50%⭐⭐ 中等
组件缓存⬆️ 渲染时间减少 40-60%⭐⭐⭐ 较难
代码分割⬇️ 首屏 JS 体积减少 50%⭐ 简单
Gzip 压缩⬇️ 传输体积减少 70%⭐ 简单
集群模式⬆️ 吞吐量提升 200-400%⭐⭐ 中等
CDN 缓存⬇️ 服务器压力减少 80%⭐⭐ 中等

9. 实战优化清单

✅ 代码层面
□ 组件使用 v-once 缓存静态内容
□ 重计算放在 onMounted 中
□ 使用 v-memo 缓存 DOM
□ 路由组件懒加载

✅ 构建层面
□ 启用 gzip/brotli 压缩
□ 分割第三方库(vendor chunk)
□ 图片/字体等资源优化

✅ 服务器层面
□ 页面缓存(LRU)
□ 流式渲染
□ 启用 Node.js cluster
□ 使用 PM2 进程管理

✅ 网络层面
□ CDN 加速
□ 资源预加载(preload)
□ HTTP/2 或 HTTP/3

✅ 数据层面
□ 合并数据请求
□ 只传输必要字段
□ API 响应缓存

10. 一句话总结

SSR 优化的核心是"减少服务端渲染负担":能缓存的就缓存,能懒加载的就懒加载,能预加载的就预加载,把压力从服务器转移到 CDN 和浏览器。

http://www.cnnetsun.cn/news/3044924.html

相关文章:

  • MATLAB fmincon函数实战调优指南:从算法选择到性能调优
  • (二)PID控制中的积分饱和:从现象到Anti-windup策略
  • 售前方案能不能用Codex和Claude半自动生成?客户需求到报价说明实战
  • 玉溪黄金白银回收铂金旧金回收无套路门店 TOP 榜单 实地测评资料整理
  • 【C 语言】文件操作 ( fread 函数进阶:缓冲区策略与错误处理 )
  • ESP32 SSD1306 OLED显示驱动深度解析:5大实战优化策略与高级应用指南
  • 告别钝刀子:深度调优 VCenter Web Client 性能与超时策略
  • 汉王四大产品行业痛点及用户痛点汇总
  • LocalVocal OBS插件深度解析:本地AI语音转字幕技术实现与性能优化
  • GEE实战:一键获取与处理全球高精度NASADEM高程数据
  • 深度剖析CVE-2025-24813:Tomcat反序列化漏洞的源码级攻防实战
  • 解构GnuRadio OQPSK解调:从理论到源码的时钟恢复精要
  • [技术前沿] GaussianEditor:如何用分层高斯与语义追踪重塑3D编辑的精度与效率
  • STM32 HAL库驱动AD7606:SPI时序解析与避坑实践
  • Web登录加密逆向实战:从CryptoJS到Python复现的完整流程
  • STM32H743+CubeMX-主从定时器联动:TIM1精准输出PWM,TIM2无中断同步计数
  • Hi7011替代H5112C:更高电压、更大电流与65536级高辉调光的国产升级方案
  • 如何轻松备份你的得到APP课程:dedao-dl完整指南
  • ComfyUI-KJNodes完整指南:终极自定义节点集合提升AI图像工作流效率
  • ESP32 SSD1306 OLED驱动开发实战:从硬件认知到创意实现的深度进阶指南
  • 【课程设计/毕业设计】基于前后端分离的老年养护服务管理系统的设计与实现 养老院日常事务智能管理系统的设计与实现【附源码、数据库、万字文档】
  • BetterNCM安装器终极指南:5分钟解锁网易云音乐插件生态
  • 爱马仕智能体 hermes 5 分钟部署 | 免代码、免命令
  • Vivado功耗报告深度解读:从Report Power到系统级能效优化
  • 清华 ManiSkill、北大 PKU-MMD 等国内开源项目解读
  • Navicat Premium试用重置:如何快速恢复14天免费试用期
  • 软考2025报考门槛巨变(高级职称取消论文硬要求?官方文件深度拆解)
  • 从零搭建NXP LPC54114开发环境:Keil5实战与LED驱动解析
  • UVa 615 Is It A Tree
  • 【Unity3D性能调优】Quality设置实战:从参数解析到多平台适配策略