我们的Vue 3项目上线之后性能很差,首屏加载要好几秒,页面切换也卡顿。经过一系列优化之后,性能提升了很多。本文是我们的Vue 3生态性能优化实战总结,包括构建优化、运行时优化、组件优化、路由优化、状态管理优化等。如果你也在用Vue 3,遇到了性能问题,希望这篇文章能帮到你。
一、项目背景
先说说我们的项目情况。
我们的项目是一个中后台管理系统,用Vue 3 + Vite + Vue Router + Pinia + Element Plus开发。项目有几十个页面,上百个组件,代码量比较大。
上线之后发现性能问题很严重:
- 首屏加载时间要5到8秒,用户体验很差
- 页面切换的时候有明显的卡顿
- 某些复杂页面(比如数据表格)渲染很慢
- 打包之后的JS文件很大,有好几MB
老板要求优化性能,目标是首屏加载控制在3秒以内,页面切换流畅不卡顿。
我负责这次性能优化,花了两周时间,从构建到运行时做了全面的优化。最终首屏加载降到了1.5秒左右,页面切换也很流畅。下面就来分享一下优化的过程和经验。
二、第一步:分析性能瓶颈
优化之前,首先要找到性能瓶颈在哪里。不要上来就优化,要先分析。
我们用了几个工具来分析:
- Lighthouse:Chrome的性能分析工具,可以给出性能评分和优化建议
- Chrome DevTools的Performance面板:记录页面加载和交互的性能数据,找到耗时的操作
- Vite的打包分析:用rollup-plugin-visualizer分析打包后的文件大小,找到大的依赖
- Vue DevTools:分析组件的渲染情况,找到不必要的重新渲染
分析之后,我们发现了几个主要的性能瓶颈:
- 打包体积太大,主要是因为第三方依赖没有按需加载
- 首屏加载了所有页面的代码,没有做路由懒加载
- 某些组件没有做优化,导致不必要的重新渲染
- 图片没有优化,加载了很多大图
- 没有利用浏览器缓存,每次都要重新加载所有资源
找到了瓶颈之后,就开始针对性地优化。
三、构建优化
构建优化是性能优化的第一步,主要目标是减小打包体积,提升加载速度。
1. 路由懒加载
这是最有效也是最简单的优化。把路由组件改成动态导入,这样首屏只加载当前页面的代码,其他页面的代码在访问的时候才加载。
// 优化前
import UserList from '../views/UserList.vue'
// 优化后
const UserList = () => import('../views/UserList.vue')改完之后,首屏的JS体积减少了60%,效果非常明显。
2. 第三方依赖按需加载
我们用了Element Plus,最开始是全量引入的,导致打包体积很大。改成按需引入之后,只引入用到的组件,体积减少了很多。
// 优化前
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
// 优化后:用unplugin-vue-components自动按需引入除了Element Plus,其他第三方库也要检查,比如lodash、moment这些大库,尽量用按需引入或者替换成更小的库。比如moment可以换成day.js,体积小很多,功能差不多。
3. 图片优化
图片是很多项目容易忽略的优化点。我们的项目里有很多PNG和JPG图片,体积都比较大。
优化方法:
- 用WebP格式代替PNG和JPG,体积能减少30%到50%
- 用Vite的imagemin插件自动压缩图片
- 小图标用SVG或者字体图标,不要用图片
- 大图用懒加载,不要首屏就加载
改完之后,图片的总体积减少了一半以上。
4. 代码分割
Vite默认会做代码分割,但是可以进一步优化。把第三方依赖单独打包成一个chunk,业务代码单独打包,这样第三方依赖的chunk可以长期缓存,不会因为业务代码变更而失效。
// vite.config.js
build: {
rollupOptions: {
output: {
manualChunks: {
vue: ['vue', 'vue-router', 'pinia'],
element: ['element-plus'],
}
}
}
}5. 开启gzip压缩
在服务器端开启gzip或者brotli压缩,可以大幅减小传输体积。我们用的是Nginx,开启gzip之后,JS和CSS的传输体积减少了60%以上。
四、运行时优化
构建优化解决了加载速度的问题,运行时优化解决的是页面流畅度的问题。
1. 组件懒加载和异步组件
除了路由懒加载,一些不常用的大组件也可以用异步组件,需要的时候才加载。比如弹窗、抽屉、复杂的编辑器等。
<script setup>
import { defineAsyncComponent } from 'vue'
const BigEditor = defineAsyncComponent(() => import('./BigEditor.vue'))
</script>2. 避免不必要的重新渲染
Vue 3的响应式系统已经很高效了,但是如果使用不当,还是会有很多不必要的重新渲染。
常见的优化方法:
- 用v-show代替v-if(频繁切换的场景)
- 用key来优化列表渲染,key要用唯一的ID,不要用索引
- 用computed缓存计算结果,避免重复计算
- 大列表用虚拟滚动,不要一次性渲染所有数据
- 用shallowRef和shallowReactive来减少大对象的响应式开销
我们有一个数据表格页面,一次渲染几百行数据,很卡。后来用了虚拟滚动(vue-virtual-scroller),只渲染可视区域的行,性能提升了很多。
3. 合理使用响应式API
Vue 3的ref和reactive很方便,但是不要滥用。
- 不需要响应式的数据就不要用ref,用普通变量就行
- 大对象用shallowReactive,只需要顶层响应式
- 大量数据用markRaw标记,不做响应式转换
我们有一个场景是从接口拿到大量数据,存到ref里,导致响应式转换很慢。后来用了shallowRef,只在需要的时候手动触发更新,性能提升了很多。
4. 防抖和节流
对于频繁触发的事件,比如输入、滚动、resize,要用防抖或者节流。
import { debounce } from 'lodash-es'
const handleSearch = debounce((value) => {
// 搜索逻辑
}, 300)我们的搜索框最开始是每次输入都发请求,导致请求很多,页面也卡。加了防抖之后,体验好了很多。
五、路由优化
1. 路由懒加载
前面已经说了,路由懒加载是必须的。
2. 路由预加载
对于一些用户很可能访问的页面,可以在首屏加载完成之后,用浏览器的空闲时间预加载。这样用户点击的时候,代码已经加载好了,切换很快。
Vite可以用magic comment来指定预加载:
const UserList = () => import(/* webpackPrefetch: true */ '../views/UserList.vue')3. 路由切换动画优化
路由切换的时候,如果有动画,要注意动画的性能。用CSS transform和opacity来做动画,不要用top、left这些会触发重排的属性。
六、状态管理优化
我们用的是Pinia,Vue 3官方推荐的状态管理库。
1. 合理设计store
不要把所有数据都放到一个store里,按照业务模块拆分store。每个store只存相关的数据,避免不必要的全局响应式。
2. 避免在store里存大量数据
store里的数据都是响应式的,如果存大量数据,会有性能开销。大量数据最好存在组件里,或者用shallowRef。
3. 用computed派生状态
需要从state派生的数据,用getter(computed),不要在组件里重复计算。Pinia的getter是有缓存的,只有依赖变化的时候才会重新计算。
七、网络优化
1. HTTP缓存
静态资源(JS、CSS、图片)设置长期缓存,文件名带hash,内容变化的时候hash变化,缓存自动失效。这样用户第二次访问的时候,静态资源直接从缓存读,不需要重新下载。
2. 接口缓存
对于不常变化的接口数据,可以做前端缓存。比如字典数据、配置数据,请求一次之后缓存起来,下次直接用缓存。
3. 接口合并和预请求
减少接口请求的数量,能合并的接口就合并。首屏需要的数据,可以在页面加载之前就预请求,不要等组件渲染的时候才请求。
八、优化效果
经过两周的优化,我们的项目性能提升很明显:
- 首屏加载时间:从5-8秒降到了1.5秒左右
- 打包体积:从3MB降到了800KB(gzip之后250KB)
- 页面切换:基本无卡顿,很流畅
- 复杂表格页面:渲染时间从几秒降到了几百毫秒
- Lighthouse性能评分:从30多分提升到了90分以上
老板对优化结果很满意,用户体验也提升了很多。
九、经验总结
这次性能优化,我总结了一些经验。
1. 先分析再优化
不要上来就优化,先找到瓶颈在哪里。用工具分析,用数据说话,针对性地优化,效率最高。
2. 构建优化性价比最高
路由懒加载、按需引入、图片压缩这些构建优化,改起来简单,效果明显,是性价比最高的优化,应该优先做。
3. 运行时优化要谨慎
运行时优化(比如shallowRef、虚拟滚动)改起来比较复杂,而且可能引入bug。要在确实有性能问题的地方做,不要过度优化。
4. 性能优化是持续的过程
性能优化不是一次性的工作,项目在不断迭代,新的代码可能会引入新的性能问题。要建立性能监控机制,定期检查,持续优化。
5. 关注用户体验
性能优化的最终目标是提升用户体验,不是为了追求数字。有些优化虽然指标好看,但是用户体验没提升,就没有意义。要从用户的角度出发,关注真正影响体验的地方。
十、写在最后
Vue 3的性能已经很好了,但是如果项目大了、代码写得不规范,还是会有性能问题。性能优化是一个系统工程,需要从构建、运行时、网络等多个方面入手。
希望我们的优化经验能帮到正在做Vue 3性能优化的你。记住,先分析再优化,用数据说话,针对性地解决问题。
最后用一句话结束本文:"性能优化没有银弹,只有持续的关注和改进。"愿每一个前端开发者都能做出又快又好的应用。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录