ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Vue3 性能优化实战:从加载性能到运行时调优的完整链路

Vue3 性能优化实战:从加载性能到运行时调优的完整链路 我不太确定该把这个内容分类到哪个目录下所以暂时先放在这里。这一章的内容其实是整个 Vue3 系列里我拖得最久的一章。不是因为性能优化本身有多难写而是市面上聊 Vue3 性能优化的文章十篇里有八篇都停留在“v-for 加 key”“避免不必要渲染”这种层级干货密度约等于零。剩下的两篇则直接甩一堆英文文档链接抄都不好抄。所以这一章我想换个思路来讲。不从理论体系出发而是从一个我实际接手过的、已经线上运行了大半年的真实项目出发记录我在排查卡顿、优化加载速度时真正用到了哪些手段踩过了哪些坑以及最后每一项优化到底产生了多大的实际收益。先说一下这个项目的背景。这是一个基于 Vue3 TypeScript Vite 开发的中后台管理系统单页面应用不算特别重但也不轻。页面数量在 80 个往上全局注册了 40 多个组件公共依赖包括了 ECharts、Element Plus、Day.js、lodash-es 这些常见库。系统跑起来之后体感很明显的两个问题一个是首屏加载白屏时间太长另一个是表格页面在数据量过千行以后滚动和勾选有明显的粘滞感。这也是我写这一章的原因——这些问题不是某个单一配置能解决的而是涉及到了 Vue3 从编译、响应式、组件设计、打包策略到运行时调优的完整链路。我会把这套链路里我验证过有效的方案、参数、代码片段全部整理出来包括具体的踩坑记录和优化前后的数据对比。内容会稍微长一点但每个点我都会讲清楚“为什么这样做”和“实际效果是多少”。1. 先说结论从哪几个维度判断一个 Vue3 项目的性能瓶颈性能优化最怕的就是瞎猜和“我只改一处”。我的习惯是先拉一份量化数据再根据数据判断瓶颈落在哪个层级。根据我最近两年的经验Vue3 项目几乎所有的性能问题都可以归结到下面这四个维度里。1.1 加载性能用户要等多久才能看到东西这一维度衡量的是从用户输入网址到首屏内容渲染完成的时间。核心指标包括首屏时间、白屏时间、资源总大小、HTTP 请求次数。中后台项目里最常见的加载性能问题就是打包后的 JS 文件超过了 1MB 甚至 2MB导致用户在低网速下长时间白屏。我在做优化前第一件事就是打开 Chrome DevTools 的 Network 面板配合 Lighthouse 做一次基准测试记录下加载时间、资源数量、各资源的加载耗时。注意要去勾选 DevTools 里的 Disable cache并且使用无痕窗口避免缓存和浏览器插件干扰数据。1.2 渲染性能页面操作时会不会觉得卡渲染性能关注的是页面在交互过程中的流畅度。比如输入框敲字是否有延迟、表格滚动是否掉帧、弹窗打开是否顿了一下。这类问题在 DevTools 的 Performance 面板里能看得很清楚可以录制一段交互过程查看里面的 FPS、长任务数量和每帧的耗时。这里我想强调一个很多文章不会告诉你的点大多数人不熟练看 Performance 面板所以经常把网络请求慢的问题误判成渲染性能问题。如果点击一个按钮后耗时很长要先去 Console 里用 performance.now() 分别测一下事件的派发耗时和网络请求耗时确定瓶颈到底在哪一层。1.3 内存性能页面长时间运行会不会越来越卡内存问题在中后台项目里极其常见表现形式是页面刚打开时一切正常但操作了半小时、一小时后逐渐变得卡顿甚至直接崩溃。这类问题跟组件销毁、事件监听、全局定时器、闭包引用等都有关系。内存问题排查主要靠 Chrome DevTools 的 Memory 面板做堆快照对比定位到持续增长且没有被释放的对象。说句实在话内存问题是最难在开发阶段发现的一类问题。因为开发时页面通常不会长时间挂机运行而且 HMR 和代码编译也会干扰内存表现。我后面会单独讲一个线上环境才容易复现的 memory leak 案例。1.4 构建性能开发调试和发版等不等人构建性能经常被忽略但它真真切切影响团队的开发效率和发布节奏。我见过一个 Vite 项目启动要等 60 多秒改一行代码热更新要四五秒整个团队每天都在等编译。构建性能优化的重点在依赖预构建、构建缓存、组件懒加载拆包这几个方向上。这四类性能问题在我的项目里都不同程度地踩到了。下面我按优化实施的顺序把这套“组合拳”完整地拆给大家看。2. 加载性能优化从 4.8s 到 1.8s我做了哪几件事加载性能是所有性能优化里优先级最高的一项因为它直接决定用户的第一印象。我的优化目标是把 Lighthouse 里的首屏时间从 4.8 秒压缩到 2 秒以内。最终做到了 1.8 秒左右整体打包体积从 2.9MB 降到了 1.2MB 以下。2.1 手动 chunk 拆包把大文件拆成合理粒度很多项目首屏慢的根源是把所有依赖都打包到了同一个 JS bundle 里导致浏览器必须下载完这个 1.5MB 的“巨无霸”才能开始解析和执行。对 Vite 项目而言默认的打包配置在 dependencies 比较多的情况下会输出一个不算小的单文件。我做的第一件事就是在 vite.config.ts 的 build.rollupOptions.output.manualChunks 里手动拆包。拆包的核心逻辑是把不会频繁变动的第三方库单独拆出来利用浏览器的强缓存让用户二次访问时直接命中本地缓存。我实际用的拆包策略是按“功能域”来拆而不是一股脑地把所有 node_modules 塞进一个 vendor 文件里。Element Plus 拆一组、ECharts 拆一组、其他业务用到的第三方库单独拆一组。这样做的好处是如果后续只升级了 Element Plus其他组件的缓存依然有效不会因为单一依赖变化牵一发动全身。// vite.config.ts 核心配置 build: { rollupOptions: { output: { manualChunks: { vue: [vue, vue-router, pinia], element: [element-plus], echarts: [echarts, vue-echarts], utils: [lodash-es, axios], }, }, }, }这里有一个非常容易踩的坑拆包粒度太细会导致请求数暴增。HTTP/2 虽然支持并发多路复用但每个文件依然有对应的解析和执行成本。我测过把每个第三方库都单独拆成一个 chunk 的场景结果首屏时间不但没有下降反而因为请求了太多小文件导致性能更差。所以拆包要遵循“按主次拆七到十份”的平衡原则而不是越细越好。2.2 路由级代码分割 异步组件让页面按需加载拆包只解决了第三方依赖的体积问题业务代码本身也得做分割。Vue3 配合 Vue Router 提供了非常优雅的 lazy loading 方案核心逻辑就一句话让当前路由的页面组件只在路由被访问时才去加载对应的 JS 文件。代码示例很简单在路由表的 component 配置里改成动态 import 就行const routes [ { path: /dashboard, name: Dashboard, component: () import(/views/dashboard/index.vue), }, // 其他路由同理 ]这一步做完之后首屏只加载 dashboard 一个页面的代码剩余 80 多个页面的代码块全部延后到用户实际访问时才加载。配合上面说的第三方库拆包首屏不再需要下载“所有代码”只下载“当前页面所需的代码”这是首屏时间从 4.8s 往下降的最关键一步。除了路由级懒加载我还把项目中一些体积较大的组件也改成了异步组件。比如项目里那个接收 Markdown 的编辑器组件体积有 120KB 左右但只有少数几个页面会用到。通过 Vue3 内置的 defineAsyncComponent API可以在组件渲染时动态引入script setup import { defineAsyncComponent } from vue const MarkdownEditor defineAsyncComponent(() import(/components/MarkdownEditor.vue)) /script template MarkdownEditor v-modelcontent / /template异步组件配合路由懒加载还有一个额外的好处它天然把组件之间的代码做了隔离。即使某个懒加载的组件加载报错也不会影响整站运行。我在调整完这层之后首屏 JS 总体积从 2.9MB 下降到了 1.6MB 左右。2.3 组件库按需导入别再把整个库全部引入这里我要聊一下中后台项目里最常见的性能浪费组件库的全量引入。很多 Vue3 项目在 main.ts 里习惯性地写成app.use(ElementPlus)然后在代码里只用了里面的 20 多个组件。Element Plus 全集大概有 4MB 以上的体积打包进产物里之后性能瓶颈可以说是“与生俱来”的。规避全量引入的方案比较主流的是安装unplugin-vue-components和unplugin-auto-import这两个插件。它们能帮你在编译阶段自动完成按需导入不用手写import { ElButton } from element-plus。配置也简单在 vite.config.ts 里加上插件即可import { ElementPlusResolver } from unplugin-vue-components/resolvers Components({ resolvers: [ElementPlusResolver()], })做完这个改造之后打包产物里就只会保留实际用到的组件和对应的样式文件。实测下来Element Plus 相关体积从 1.2MB 降到了 400KB 左右。同时要注意Element Plus 的 MessageBox、Message、Notification 这类函数式组件即使不显式引入也会被全量打包进去。遇到这种情况可以用一个全局的 API 类型声明文件按需从element-plus/es路径引入函数这部分的细节比较碎遇到问题了可以逐个排查。2.4 启用 CDN 加速和静态资源压缩把打包产物放到 CDN 上是加载性能提升里最轻松、最立竿见影的一步。CDN 的核心作用是让用户从“地理位置上最近的节点”获取资源而不是每次都从你的应用服务器跨地域拉取。我的项目是在 Nginx 层面对/assets/路径做了 CDN 回源配置静态资源全部缓存 30 天效果是上海、深圳两地的同事都能保持 1 秒左右加载完成。同时我在构建层做了 Gzip 压缩Nginx 配置开启 gzip_static 后可以直接让服务器返还预先压缩好的 .gz 文件省掉实时的 CPU 压缩开销。这里有个实战细节Vite 默认产物不带 .gz 后缀需要额外装vite-plugin-compression插件。如果你还想进一步压体积可以考虑使用 Brotli 算法它的压缩率比 Gzip 更高在支持 Brotli 的现代浏览器里能省 15% 到 20% 的体积。资源加载这块我还有一个冷门但好用的技巧给关键的 CSS 资源加上preload给首屏用不到的替代资源加上prefetch。不要低估这些小细节在中后台项目里主 JS 文件的加载优先级直接影响白屏时间。合理的 preload 能让浏览器尽早发现并下载关键资源不让它排队等后面的资源解析。3. 编译优化与响应式原理让 Vue3 的“快”真正落地很多人面试时能把响应式原理背得滚瓜烂熟但实际项目里写出来的代码却反过来绕过了 Vue3 最擅长的优化路径。Vue3 的编译器本身已经做了静态标记、静态提升、事件缓存这些编译层的优化我们要做的就是理解这些优化机制在写代码时别去破坏它。3.1 理解编译器做了什么才能不写“反优化”代码Vue3 的模板编译器和 Vue2 最大的不同是它在编译阶段就为动态节点打上了 PatchFlag 标记。这个标记直接告诉运行时“这个节点的 class 可能会变”“那个节点的 text 可能会变”这样一来diff 算法在比对时就不需要再深入子节点逐个查找变化只需要精准更新标记过的字段。我自己写项目的时候对编译器标记其实有一个“三大不写”的总结模板里不要写太深、太复杂的表达式逻辑全部提到 computed 或函数里计算好再渲染。静态区域的 class 和 style 不需要动态绑定能写死就写死。不要在模板里调用一个会返回新对象的函数比如:listgetList()因为每次渲染都会生成新引用导致子组件不断重渲染。第三个点尤其隐蔽我见过不止一个项目因为getList()这种写法导致子组件无限地触发子组件的 effect页面一操作鼠标就卡。本质原因是 Vue3 的响应式更新依赖精确跟踪依赖变化而模板函数调用每次都返回一个新数组引用打破了引用稳定性。正确做法是把 getList 改成 computed 或者在 setup 里定义好并保持引用不变。3.2 用好 shallowRef减少深层响应式监听的开销Vue3 的 ref 和 reactive 会在对象嵌套层级很深时创建大量的代理对象。对于正常业务数据这点开销完全可以忽略但如果你是做可视化大屏、实时图表刷新的场景频繁修改一个很大的响应式对象就会触发一整条依赖链路的更新。这里引入 shallowRef 是合适的选择。shallowRef 只监听 .value 的变化不会对 value 的内部属性做深层次代理。比如一个图表配置对象内部有几千个配置字段如果我只关心整体替换配置那就用 shallowRef 包它然后每次更新时直接替换整个对象。import { shallowRef } from vue const chartOption shallowRef({ // 一个非常大的配置对象几十 KB 数据 }) // 正确做法整体替换触发依赖更新 chartOption.value { ...chartOption.value, series: newSeriesData, } // 错误示范直接在内部修改shallowRef 检测不到 // chartOption.value.title.text 新标题这个思路和 React 里“immutable 更新”很像。项目里如果有一处高频更新但结构很深的数据用 shallowRef 之后响应式系统的代理创建和依赖收集开销都会大幅减少。我自己的大屏页面在改用了 shallowRef 之后渲染帧率从 34fps 提升到了 55fps 左右体感从“明显卡顿”变成了“丝滑流畅”。3.3 v-memo 和 v-once给超长列表加一层“免检”保险v-memo 是 Vue3.2 引入的指令用来按条件缓存虚拟节点。它的工作原理可以简单理解成传入一个依赖数组如果数组里的每个值都没变化则整个子树直接跳过 patch 过程。这比 key diff 更激进更适合那些数据量大、但是每次更新只有局部变化的场景。我在一个待办审核列表里试过 v-memo。列表有五百多行每行除了展示数据之外还有一个“通过/驳回”按钮。业务要求是用户点击通过之后这个按钮的 loading 状态要立刻切换但其他行的内容完全不用变。于是我在这一行节点上加了v-memo[item.status]让列表只在当前行的 status 变化时才重新渲染当前行。实测下来的长列表操作不再有明显掉帧。v-once 的使用更干脆它的意思是“渲染一次以后再也不变”。像页面的页头、静态说明文案、版本号这类纯静态内容直接加 v-once 可以免掉它们的重复 render 和 diff。这两个指令是编译和运行时层面都很契合的“免检通道”但要注意滥用 v-once 会导致内容永远无法更新所以只推荐用于真正静态的内容。3.4 非响应式数据放“外部”尽量缩小响应式范围我在小型的组件里几乎只在需要响应式的核心状态上用 ref/reactive其余辅助数据、常量、计算中间量全部放在 setup 外部的模块作用域里。这样做的原因很简单响应式系统的 Proxy 拦截有开销依赖收集也要占用内存。数据量小的时候无所谓但当组件数量多了以后每一个非必要的 reactive() 都会为项目增加可察觉得到的内存和性能负担。特别说明一下如果你有一些不会在模板里动态变化的数据完全没必要塞进 reactive 里。直接定义一个普通对象甚至用static思想把它提到模块顶层就行。比如一个下拉选项的字典数组、一个根据权限码映射的菜单配置这些统统不需要变成响应式。我用这个思路清减了项目里很多“为了响应式而响应式”的写法代码可读性反而提高了。4. 运行与组件层优化用更合理的方式写业务减少不必要的更新响应式和编译层优化的前提都需要组件的写法足够“合理”。这一部分重点讲运行时和组件封装层面的优化手段。这块的优化不像拆包、按需导入那样能立竿见影但它是决定一个项目好不好维护、长不长时间运行会不会卡的根基。4.1 正确使用 computed 和 watch避免副作用乱飞computed 在 Vue3 里是带缓存的只有依赖变化时才会重新计算。这是属于 Vue3 响应式系统的内置性能保障。我有一个强烈的建议凡是能从现有响应式数据推导出来的值一律优先用 computed 而不是用 watch 手动赋值。watch 的问题在于它适合处理“副作用”比如拉接口、操作 DOM、写日志。如果你用 watch 去同步一份 state相当于把数据的派生逻辑分散到了多个地方很容易出现一处更新、多个 watcher 连锁触发的情况。我在项目里见过一次因为 watch 里改了另一个响应式数据然后该数据又触发了别的 watcher最后无限循环导致页面直接卡死的案例。排查起来极其痛苦。还有一个实战小技巧watch 默认是惰性的但如果你用 watch 监听一个引用类型默认情况下只有引用变化才触发。需要深层监听时记得配置 deep: true但要注意 deep 监听会递归遍历对象比较消耗性能。对于大数据对象的深度监听我一般会选择在数据源头做不可变更新然后用 shallow ref 代替 deep watch性能会好很多。4.2 用 keep-alive 缓存组件减少重复创建开销中后台项目里最常见的一个操作模式是从列表页跳详情页再返回列表页。如果不做任何处理每次返回列表页时组件都要重新创建、重新拉接口、重新渲染用户会明显感觉到闪一下。在 Vue3 中用 keep-alive 包裹 router-view可以缓存页面组件的状态让用户从详情页返回列表时直接恢复到离开时的滚动位置和数据状态不会再重新渲染一遍。这一层优化对交互体感的提升非常大。router-view v-slot{ Component } keep-alive :includecachedViews component :isComponent / /keep-alive /router-view注意 keep-alive 的 include 数组不是“全都缓存”而是要按需缓存。把所有页面全部缓存之后内存占用会持续增长因为每个组件的实例、状态、DOM 结构都会被保存在内存里。我的做法是在路由元信息里配置 meta.keepAlive然后动态维护一个缓存名单。这样既能精确控制哪些页面需要缓存又防止内存无限膨胀。Keep-alive 还有一个容易踩坑的地方被缓存的组件在激活和失活时会触发 onActivated 和 onDeactivated 两个新的生命周期钩子。如果你页面的数据需要保持最新应在 onActivated 里去刷新数据而不是放在 onMounted 里因为 keep-alive 缓存之后 onMounted 只在第一次创建时执行。我以前把刷新逻辑写在 mounted 里结果从详情页返回时总显示旧数据排查了好久才发现是这个原因。4.3 事件绑定与监听器的正确清理事件监听的坑在 Vue2 时代就存在Vue3 的 Composition API 让组件销毁逻辑变得更集中了但依然很多人没养成清理习惯。比如在 setup 里手动写了window.addEventListener(resize, handler)组件销毁时不 remove那么页面里每打开关闭一次该组件就会累积一个监听器。时间长了之后内存占用越来越高页面操作也会越来越迟钝。正确的做法是在 setup 里使用 onBeforeUnmount 或 onUnmounted 统一做清理import { onMounted, onUnmounted } from vue const resizeHandler () { // 处理逻辑 } onMounted(() { window.addEventListener(resize, resizeHandler) }) onUnmounted(() { window.removeEventListener(resize, resizeHandler) })如果你用的是 ECharts、地图实例这类带复杂生命周期的第三方实例更要在组件卸载之前执行实例的 dispose 方法。我的做法是在使用图表的组件里onUnmounted 里统一调用chart.dispose()并把 chart 置为 null保证实例被垃圾回收。4.4 大数据列表渲染优化虚拟滚动当列表数据超过一百条直接渲染会产生大量 DOM 节点页面渲染和滚动都会变得吃力。表格页里的上千行数据直接一次性渲染所有 tr/td会在浏览器里创建成千上万个 DOM 元素每帧滚动都要重排和绘制不卡才怪。虚拟滚动方案的核心思想是只渲染可视区内的节点。比如列表总共有 1000 条可视区只能看到 10 条那就只渲染 10 条加一点缓冲条滚动时动态计算当前应该渲染的数据同时通过撑起一个总高度来模拟滚动条。如果不想自己造轮子中后台项目我推荐直接用 vue-virtual-scroller 这个库。它和 Vue3 配合得不错核心组件 VirtualScroller 可以接收 items 数组、item 高度、可见区高度等参数空态、大数据量都处理得比较好。template VirtualScroller :itemslist :item-height50 v-slot{ item } div classrow{{ item.name }}/div /VirtualScroller /template还有一种适用于表格的轻量方案el-table-v2它是 Element Plus 官方提供的虚拟化表格组件适合处理超大表格。我做的项目里最重的表格有 5 万行数据用 el-table-v2 之后滚动很顺滑性能和体验都得到了保证。5. 内存与运行时疑难杂症排查实录如果说前面的优化是“主动预防”那内存泄露和疑难杂症的排查就是“被动救火”。这一部分我结合真实线上环境遇到过的两个典型问题分享一下求助过的排查思路和具体解决过程。5.1 线上偶现页面崩溃打开 Memory 面板定位到反复销毁的弹窗组件我们有一个表单弹窗打开一次再关闭一次然后用 Performance Monitor 看内存。发现 JS Heap 的曲线是锯齿状的——也就是说打开弹窗内存峰值上升关闭弹窗理论上应该回落到原来的水平但实际曲线每次回退都比前一个周期高一点。这就意味着每次打开关闭都会有一小部分内存没被回收。通过 Memory 面板录制堆快照然后对比打开弹窗前后的两份快照我发现问题出在弹窗内部的图表组件关闭弹窗时子组件的 v-if 确实移除了 DOM但图表实例的 event handler 还挂在 window 上。因为没有执行 dispose图表实例无法被垃圾回收事件队列里始终留着它的引用。这个问题在开发环境里完全不明显因为打开一次弹窗多消耗的内存只有几 MB除非连续开关几十次否则看不出来。但生产环境用户可能会一整天都在使用系统几十次甚至上百次的弹窗积累下来内存膨胀到一定程度浏览器就会强制崩溃掉。最终修复方式其实很简单我给弹窗组件添加了 onUnmounted 钩子在里面执行 chart.dispose()并移除所有手动绑定的 window 事件。修复后再次录制堆快照曲线就稳定了。5.2 老组件里隐藏的“闭包引用”把 200 个实例全部留在了内存里还有一次排查是被一个自定义指令拖垮的。项目里有一个 v-debounce 指令用来给按钮点击做防抖处理内部实现是每绑定一次就创建一个 setTimeout 闭包。这个指令本身也没什么问题但有一个页面用了这个指令的组件是被 keep-alive 缓存的keep-alive 缓存了这些组件实例同时也缓存了它们闭包里引用的对象。组件要销毁时keep-alive 会阻止销毁导致闭包引用一直存在无法释放。这个案例提醒我一个点自定义指令、事件绑定这些“无感知”的代码是最容易产生内存泄漏的高发区。排查思路可以总结为四步先看是否频繁创建监听器或定时器再看组件的销毁逻辑是否齐全然后观察多次操作后内存是否单向上涨最后通过 Memory 快照对比定位增长对象。5.3 性能优化的最后一道防线用 DevTools 量化每一项改动在我给出性能优化建议之前我不太信任“感觉”。一切优化做完之后都要回到数据本身去验证。Chrome DevTools 的 Performance 面板录完一段操作记录之后要重点看这几项指标指标说明理想值FPS页面帧率低于 30 说明明显卡顿稳定在 50 以上LCP最大内容绘制时间衡量首屏加载2.5s 以内JS HeapJS 堆内存关注是否存在持续上升波动在合理区间Scripting 时间脚本执行耗时决定交互响应速度单次长任务不超过 50ms这个表格是一个方便你抄走的检查维度。我每次优化完一个项目都会用这四项数据做前后对比然后记录在项目文档里。这样做的好处是以后出现性能回归时可以非常明确地看出是哪个环节掉了链子不用再从头排查一遍。另外再三强调一下DevTools 在无痕模式下测试最准。浏览器插件、本地缓存、跨域状态都会影响数据真实性这些外部变量不控制你测出来的数字基本没有参考价值。6. 构建与工程配置层面的性能细节代码写得好只能代表运行时很流畅。如果每次构建发布慢到让人崩溃同样会影响交付效率。所以 Vue3 项目性能优化的闭环不能漏掉构建工程层面的细节。6.1 Vite 依赖预构建与缓存策略Vite 在本地开发时用 esbuild 对 node_modules 做依赖预构建你启动项目时有第一次慢启动的过程后续访问就会快很多。这个预构建结果默认缓存在 node_modules/.vite 目录里。如果你改了 vite.config.ts 的某些配置或者新增了依赖缓存不会自动生效可能遇到“改了配置但开发服务器没反应”的情况。解决办法是删除 .vite 缓存目录后重启或者在 vite.config.ts 里设置server.force为 true。生产构建方面Vite 会默认用 Rollup 的 tree-shaking 机制剔除未使用的 ESM 导出。要保证 tree-shaking 能生效你的第三方依赖必须是 ESM 格式的如果依赖是 CJS 或者 UMD基本上无法被 tree-shaking。这一点在引入老旧的、不支持 ESM 的库时要特别留意。6.2 区分开发依赖和生成依赖依赖装错位置是一个很常见的问题。比如一些只在开发时用的工具eslint、typescript、vite-plugin-compression如果被装到了 dependencies 里构建时虽然不会打进产物但会影响依赖安装大小版本管理器锁定的时间。养成习惯——跟构建工具相关的装 devDependencies运行时要用的装 dependencies能让你安装依赖的速度快很不少。6.3 图像和静态资源处理Vue3 项目里占比最大的静态资源往往是图片。如果图片是几 MB 的 PNG 或者未压缩的 JPG再怎么优化代码也掩盖不了网络传输的成本。我的惯例是超过 20KB 的图片统一用 CDN 存放不放进打包产物里。打包产物里的图片走构建压缩用 Vite 的 rollupOptions 配置好资源内联阈值小于 4KB 的图片会转为 base64能减少请求数大图则全部走 CDN 链接。另外项目里如果有 svg 图标推荐使用 vite-plugin-svg-icons 这个插件把 SVG 统一雪碧图化。它可以把多个 SVG 拼合到一个 symbol 里在运行时通过use引用避免每个图标都单独发起一次 HTTP 请求也能让图标颜色跟随 CSS 动态控制比直接放 img 标签灵活得多。7. 项目真实优化数据总结这是我个人对这轮优化的复盘这轮优化到底产生了什么效果我拿优化后的真实数据来给各位做个复盘。整个优化从打包策略、代码分割、按需导入、组件运行、内存调优做了大概三周中间穿插了日常功能的并行开发。指标优化前优化后降幅首屏 JS 总大小2.9MB1.1MB62%Lighthouse 性能评分6894—首屏加载时间4.8s1.8s62%表格页面滚动帧率28fps52fps85%弹窗开关 20 次后内存增长45MB3MB93%这组数据是可以直接作为你优化项目的参考基准的。比如你优化前的首屏时间和体积如果跟我优化前的量级差不多那么按我在第 2 章里讲的方法做一遍大概率也能达到跟我一致甚至更好的效果。性能优化从来不是一个一锤子买卖它是持续迭代的过程。可以看了一眼自己的项目按我上面列出的维度先测一轮数据挑性价比最高的点开始优化。如果哪一步卡住了多去翻翻 Vue3 的官方文档和 DevTools 的报告很多答案其实都在那里等着你。
返回列表