最近接手了一个Vue 3的项目,性能问题很严重。页面加载慢,交互卡顿,用户投诉很多。我花了两周时间,对这个项目进行了一次彻底的性能优化,把首屏加载时间从8秒降到了2秒,页面交互也流畅了很多。
这篇文章我想分享一下这次性能优化的实战经验,从定位问题到具体优化,再到效果验证,记录每一个步骤。如果你也在做Vue项目的性能优化,希望能给你一些参考。
问题的现状
先说说这个项目的问题。
这是一个中后台管理系统,用的是Vue 3.6 + Vite + Element Plus。功能不算复杂,但页面很多,有几十个路由。用户反馈最多的问题是:打开页面很慢,有时候要等好几秒;切换路由的时候,会有明显的卡顿;列表数据多的时候,滚动和操作都不流畅。
我先用Chrome DevTools的Performance面板测了一下,发现了几个问题:
第一,首屏加载时间太长。从输入URL到页面完全渲染,需要8秒多。其中,JS下载和解析占了大部分时间。
第二,打包体积太大。整个项目打包之后,JS文件有3MB多,CSS文件有500KB。这么大的体积,在网络不好的时候,下载就需要很长时间。
第三,运行时性能差。页面渲染的时候,长任务很多,主线程经常被阻塞,导致交互卡顿。
第四,内存占用高。页面开久了,内存占用会越来越高,甚至会导致浏览器崩溃。
找到了问题,我就开始了针对性的优化。
第一步:分析打包体积
性能优化的第一步,是分析打包体积。因为体积太大,下载和解析就慢,首屏加载自然就快不了。
我用rollup-plugin-visualizer这个插件,生成了打包体积的可视化分析图。一看就发现了问题:
第一个问题是,整个Element Plus都被打包进去了。我们虽然只用了十几个组件,但整个组件库都被打进来了,占了1MB多。
第二个问题是,很多第三方库没有按需加载。比如lodash,我们只用了几个函数,但整个lodash都被打进来了。还有moment.js,体积也很大。
第三个问题是,所有的页面都打包到了一个JS文件里。虽然用了路由懒加载,但配置有问题,实际上没有生效。
第四个问题是,图片没有优化。有些图片很大,几MB的图片直接放在项目里,没有压缩。
找到了这些问题,我就开始逐个优化。
第二步:按需加载和代码分割
第一个优化是按需加载。
对于Element Plus,我改成了按需引入。用unplugin-vue-components和unplugin-auto-import这两个插件,自动按需引入用到的组件和样式。这样,只有用到的组件才会被打包,体积一下子减少了800多KB。
对于lodash,我改成了lodash-es,然后只引入用到的函数。比如用debounce,就只import debounce from 'lodash-es/debounce'。这样,就不会把整个lodash打进来。
对于moment.js,我直接换成了day.js。day.js的API和moment.js基本兼容,但体积只有2KB,比moment.js小太多了。
第二个优化是代码分割。
我检查了路由配置,发现懒加载确实没生效。原来的写法是component: () => import('@/views/xxx.vue'),但因为webpackChunkName的配置有问题,所有页面都被打到了一个chunk里。
我修正了配置,给每个路由都加上了正确的webpackChunkName,这样每个页面就会被打包成单独的JS文件,只有访问这个页面的时候才会加载。
我还把一些大的第三方库,比如图表库、编辑器,单独拆成了chunk。这些库只有在用到的页面才会加载,不会影响首屏。
做完这些优化之后,首屏的JS体积从3MB降到了800KB,效果很明显。
第三步:图片和静态资源优化
第二个优化是图片和静态资源。
我把项目里的图片都检查了一遍,发现有很多图片没有压缩。我用工具把所有图片都压缩了一遍,JPG用mozjpeg,PNG用pngquant,体积减少了60%以上,画质几乎没有损失。
对于一些小的图标,我改成了SVG雪碧图,或者直接用iconfont。这样,就不需要加载很多小图片了。
对于大的背景图,我用了webp格式,体积比JPG小很多。同时,做了兼容处理,不支持webp的浏览器,还是用JPG。
我还开启了Vite的assetsInlineLimit,把小于4KB的图片转成base64,内联到JS里,减少HTTP请求。
做完这些优化之后,静态资源的体积减少了一半多。
第四步:Gzip和CDN
第三个优化是开启Gzip压缩和CDN。
我在构建的时候,用vite-plugin-compression插件,生成了gzip格式的压缩文件。服务器配置了gzip之后,传输的体积又减少了60%左右。原来800KB的JS,gzip之后只有300KB左右。
对于一些不常变化的第三方库,我放到了CDN上。比如Vue、Vue Router、Pinia这些,用CDN的版本,不打包到项目里。这样,既减少了打包体积,又能利用CDN的缓存,用户加载更快。
不过,用CDN要注意版本一致性,还有要考虑CDN的可用性。如果CDN挂了,整个项目就用不了了。所以,我做了本地 fallback,如果CDN加载失败,就用本地的版本。
第五步:运行时性能优化
加载速度优化完了,接下来是运行时性能优化。
第一个问题是,列表渲染的时候,数据量大了就卡顿。我检查了一下,发现列表没有用虚拟滚动,几百条数据全部渲染出来,DOM节点很多,当然会卡。
我引入了虚拟滚动组件,只渲染可视区域的DOM节点。这样,不管有多少条数据,DOM节点的数量都是固定的,滚动和操作都很流畅。
第二个问题是,很多组件没有做缓存。切换路由的时候,组件会被销毁,再切回来的时候,又要重新创建和渲染,很慢。我用了keep-alive,把常用的页面缓存起来,切换的时候就不需要重新渲染了,速度快了很多。
第三个问题是,响应式数据用得不合理。有些不需要响应式的数据,也用了ref或者reactive,导致Vue做了很多无用的依赖收集。我把不需要响应式的数据,改成了普通的变量,或者用shallowRef、shallowReactive,减少了响应式的开销。
第四个问题是,watch和computed用得太多。有些watch,监听的数据变化很频繁,每次变化都会执行回调,导致性能问题。我优化了这些watch,加上了防抖,或者用更精确的监听方式。对于computed,也检查了有没有不必要的计算。
第五个问题是,事件监听器没有清理。有些组件在卸载的时候,没有移除全局的事件监听器,导致内存泄漏。我给每个组件都加上了onUnmounted,在组件卸载的时候,清理所有的事件监听器和定时器。
第六步:渲染优化
还有一些渲染层面的优化。
第一个是v-for的key。很多列表的key用了index,这在列表顺序变化的时候,会导致不必要的重新渲染。我把所有的key都改成了唯一的id,这样Vue能更准确地追踪节点,减少重新渲染。
第二个是v-if和v-show的使用。对于频繁切换的元素,用v-show,因为v-if会销毁和重建DOM,开销很大。对于不频繁切换的元素,用v-if,因为v-show会一直保留DOM,占用内存。
第三个是函数式组件。对于纯展示的组件,我改成了函数式组件。函数式组件没有实例,渲染开销更小。
第四个是异步组件。对于一些不是首屏必须的组件,比如弹窗、抽屉,我改成了异步组件,只有在需要的时候才加载。
第五个是CSS优化。我检查了CSS,发现有很多重复的样式,还有一些没用的样式。我清理了无用的CSS,把重复的样式提取成公共类。还开启了CSS的代码分割,每个页面的CSS单独加载。
第七步:网络请求优化
网络请求也是性能优化的重要部分。
第一个是请求合并。有些页面,会发很多个请求,每个请求获取一点数据。我把这些请求合并成一个,减少了HTTP请求的数量。
第二个是请求缓存。对于一些不常变化的数据,我做了缓存。第一次请求之后,把数据存起来,下次再需要的时候,直接用缓存,不需要重新请求。
第三个是请求防抖和节流。对于搜索、筛选这类操作,加了防抖,用户输入停止之后才发请求。对于滚动加载这类操作,加了节流,避免频繁发请求。
第四个是接口数据精简。我和后端沟通,把一些接口的返回数据精简了,只返回前端需要的字段。这样,接口的响应更快,前端处理数据也更快。
优化效果
做完这些优化之后,效果很明显。
首屏加载时间,从8秒降到了2秒。在网络好的情况下,甚至能到1秒多。
路由切换的时间,从2秒降到了200毫秒,几乎感觉不到卡顿。
列表滚动和操作,也流畅了很多。即使是几千条数据的列表,滚动也很顺滑。
内存占用也降下来了,页面开久了也不会越来越卡。
用户的投诉也少了很多,大家都说系统比以前好用多了。
性能优化的经验
这次性能优化,我总结了几条经验。
第一,先测量再优化。不要凭感觉优化,要用工具测量,找到真正的瓶颈。DevTools的Performance、Lighthouse、打包分析工具,都很好用。
第二,从最大的问题开始优化。优化要抓主要矛盾,先解决影响最大的问题,比如打包体积、首屏加载。不要一开始就纠结于很小的优化,那样收益不大。
第三,优化要持续。性能优化不是一次性的工作,要持续关注。每次加新功能,都要考虑对性能的影响。可以在CI里加上性能检查,防止性能退化。
第四,不要过度优化。优化是有成本的,有些优化会让代码变得复杂,降低可维护性。要在性能和可维护性之间找到平衡。
第五,关注用户体验。性能优化的最终目的,是提升用户体验。不要只看指标,要实际用一用,感受一下是不是真的变快了。有时候,指标好看了,但用户体验并没有提升,这样的优化是没有意义的。
写在最后
这次Vue项目的性能优化,花了我两周时间,但我觉得很值得。
从最开始的8秒加载,到最后的2秒,从最开始的卡顿,到最后的流畅,这个过程虽然辛苦,但很有成就感。
性能优化是前端开发中很重要的一部分,也是很有技术含量的一部分。它需要你对框架、对浏览器、对网络,都有深入的理解。
如果你也在做Vue项目的性能优化,希望我的这些经验能帮到你。记住,先测量,再优化,从大问题开始,持续关注,不要过度优化。
最后用一句话来结束这篇文章:"性能不是优化出来的,是设计出来的。从一开始就关注性能,比事后补救要容易得多。"
愿每一个前端开发者,都能做出又快又好用的产品。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录