跳到主要内容

Vue + Vite 项目中的性能优化

Vue + Vite 项目里谈性能优化,不能只盯着一个点。面试和实战里更好的表达方式是把问题拆成三层:

  1. 构建性能:启动慢、HMR 慢、打包慢
  2. 产物性能:首屏包太大、缓存命中差、资源加载慢
  3. 运行时性能:渲染慢、更新慢、交互卡

这篇以 Vue 3 + Vite 5/6 常见项目 为前提,讲最常用、最能落地的一套方法。

面试速答(30 秒版 TL;DR)

  • Vite 已经把“开发期构建速度”做得很好,但项目大了以后,性能瓶颈仍然会出现在:
    • 依赖预构建过重
    • 路由首屏包过大
    • 大组件和大列表重复渲染
    • 静态资源和缓存策略不合理
  • 优化顺序建议:
    1. 先定位是开发慢、构建慢还是运行慢
    2. 再针对性处理依赖、拆包、异步加载、渲染边界和资源体积
    3. 用分析工具验证,不要靠感觉

先按三层排查:开发期构建产物运行时

1. 先分类定位问题

1.1 开发期慢

常见表现:

  • pnpm start 启动慢
  • 首次打开页面慢
  • 热更新范围大、刷新频繁

1.2 构建产物慢

常见表现:

  • 首屏 JS 包很大
  • 首次加载资源多
  • 缓存命中差,每次发版都全量失效

1.3 运行时慢

常见表现:

  • 大列表卡
  • 表单输入卡
  • 路由切换卡
  • 一改状态就很多组件重渲染

先分类,才知道该改哪层。

2. Vite 侧优化:开发和构建层

2.1 控制依赖体积和依赖数量

Vite 开发期依赖预构建基于 esbuild,已经很快,但如果你引入了很多重型依赖,冷启动还是会变慢。

建议:

  • 尽量避免重复引入功能重叠的库
  • 优先使用按需能力明确的库
  • 对特别重且稳定的依赖,关注是否需要预构建配置优化

2.2 路由级懒加载

这是 Vue 项目里最划算的优化之一:

const UserPage = () => import('./pages/UserPage.vue')

这样可以把非首屏页面拆成异步 chunk,减少初始包体积。

2.3 合理拆包

生产构建阶段,重点关注:

  • 大型图表库
  • 富文本编辑器
  • 地图库
  • 组件库的重资源部分

可以结合 build.rollupOptions.output.manualChunks 做定向拆包,但原则是:

  • 先看分析结果
  • 再拆真正的大块依赖

不要为了“看起来专业”把包拆得非常碎,导致请求和缓存策略反而更复杂。

2.4 关闭不必要的产物开销

例如:

  • 生产环境不随意开启 sourcemap
  • 没必要时不要输出超多分析和调试文件
  • 避免把测试、mock、开发专用逻辑带进正式包

3. Vue 侧优化:减少无效渲染

3.1 稳定 props 和组件边界

父组件一更新,不代表所有子组件都应该跟着做重活。

要点:

  • 拆小组件,但别过度碎片化
  • 保持 props 稳定,避免每次都传全新对象/全新函数
  • 把真正频繁变的状态尽量限制在局部组件内

3.2 合理使用 computed

如果某个值是同步派生结果,就优先用 computed,不要在模板里写复杂表达式,也不要每次渲染都重复做大计算。

3.3 慎用深度 watch

deep: true 很方便,但大对象上成本可能很高。能精确监听字段,就不要对整棵对象做深度监听。

3.4 使用 v-once / v-memo

  • v-once:完全静态且后续不变的内容
  • v-memo:Vue 3 里对特定子树做条件记忆,减少重复 patch

这类优化适合:

  • 大片静态说明区
  • 复杂但更新条件明确的局部块

4. 大列表和复杂页面优化

4.1 虚拟列表

数据量很大时,真正的问题不是“JS 算不动”,而是 DOM 太多。

这时优先考虑:

  • 虚拟滚动
  • 分页
  • 分段渲染

4.2 避免一个状态驱动整页重算

很多页面卡,是因为一个输入框改一次,整页很多区域都重新求值、重新 patch。

解决思路:

  • 按业务边界拆组件
  • 把局部状态留在局部
  • 避免把整页状态都堆进同一个超大响应式对象

4.3 缓存高成本页面

对列表页、搜索页、标签页这类频繁切换页面,可结合 keep-alive 做状态复用,减少重复初始化。

5. 静态资源优化

5.1 图片优化

  • 优先控制原图尺寸
  • 使用合适格式,例如 WebP、AVIF
  • 非首屏图片懒加载
  • 雪碧图或 Base64 只适合非常小的资源

5.2 字体优化

  • 只引入需要的字重
  • 大字体文件尽量分包或延迟加载
  • 避免为了视觉细节加载过重的在线字体

5.3 CSS 优化

  • 删除无用样式
  • 控制全局样式体积
  • 避免组件库样式全量覆盖式引入

6. 接口与数据层优化

前端性能不只是渲染。

很多“页面慢”的根因其实是:

  • 接口瀑布流
  • 重复请求
  • 大 JSON 解析成本
  • 请求时机过晚

常用手段:

  • 并行请求
  • 请求缓存
  • 去重请求
  • 首屏所需数据优先
  • 非关键数据延迟拉取

7. Vite 项目里值得养成的分析习惯

不要凭感觉说“已经优化了”,最好有工具支撑。

常见思路:

  • 用打包分析工具看 chunk 分布
  • 看首屏网络 waterfall
  • 看 Lighthouse 或 Web Vitals 指标
  • 在 DevTools Performance 里看长任务和重渲染

优化应该是:

  • 先测
  • 再改
  • 再复测

8. 常见误区

8.1 只盯着 Vite 配置

Vite 只是工具链。很多真正的性能问题来自:

  • 组件边界设计差
  • 状态范围太大
  • 页面首屏塞太多业务逻辑

8.2 过度拆包

包拆得太碎,未必更快,可能只是把“大文件问题”换成“请求过多和缓存复杂问题”。

8.3 不区分开发性能和线上性能

开发期慢,不一定说明线上慢;线上首屏大,也不一定能靠 HMR 配置解决。要先区分问题所在阶段。

9. 面试高频答法

Q1:Vue + Vite 项目怎么做性能优化?

:我会先分成开发期、构建产物、运行时三层。开发期主要看依赖预构建和 HMR 范围;构建产物主要做路由级懒加载、按需拆包和静态资源压缩;运行时主要控制组件边界、减少无效渲染、优化大列表和深度 watch。最后一定配合打包分析和性能面板验证效果。

Q2:Vite 已经很快了,为什么项目还是会卡?

:因为 Vite 主要优化的是构建链路,不会自动解决业务层的无效渲染、大列表 DOM 数量、接口瀑布流、资源体积过大这些问题。工具快,不等于页面天然快。

速记要点

  • 先分层:开发期、构建产物、运行时
  • 首屏优化重点:路由懒加载、合理拆包、资源压缩
  • 运行时重点:稳定 props、组件边界、虚拟列表、减少深度 watch
  • 先分析再优化,不靠感觉