1 背景
此次优化的核心对象是基于vue-cli4的前端项目。随着业务功能的不断更新与扩展,系统规模日益庞大,导致页面加载速度相对迟缓。为了进一步提升用户的操作体验,我们特别针对系统的打开速度进行相应的前端优化工作。
利用webpack-bundle-analyzer插件分析项目当前的前端资源打包情况(如图1),结合chrome network工具的分析系统的当前加载情况,制定我们此次的优化方向,优化打包策略,提升首屏加载速度。
图1 优化前打包图
2 优化手段
系统中初始就已经做了一些优化配置,例如js,css代码压缩;开启gzip压缩;配置webpack LimitChunkCountPlugin控制chunk的最大数量,实现chunk合并,从而减少http请求数等。本文这部分不在做介绍,只介绍本次新增的内容。
2.1 第三方静态资源
对于引入html模版的静态js、css文件。
- css/js配置preload实现资源的预加载。
- js文件配置合适的async、defer属性
- css/js资源上传到CDN,CDN支持多域名及HTTP2服务。
首先在html中手动引入外部库文件。
然后,在vue.config.js中配置需要外部引入的库。
configureWebpack: { externals: { vue: 'Vue', //key表示包名;value表示window下的全局变量名 }, },
2.2 打包策略
2.2.1 dll动态链接库
通过webpack-bundle-analyzer插件分析,一些第三方库也同样打包到了业务代码中,例如,echarts、xlsx、jspdf等。将该部分库抽离出去,会减少业务代码的打包体积,并提升打包速度。配置流程如下:
1 打包配置文件webpack.dll.config.js
2 在vue.config.js中使用DllReferencePlugin将打包后的dll文件,引用到需要的预编译的依赖上来,避免在公共区域重复编译依赖。
3 package.json中配置启动命令
运行npm run dll启动打包,打包之后的文件存放在配置文件中指定的目录中public/vendor。打包后的dll文件上传到CDN服务上,在html文件中引入路径。
"dll": "webpack --config ./webpack.dll.config.js"
2.2.2 Webpack SplitChunksPlugin
Dllplugin可以把常用的库抽离出来,例如vue、vuex等。但是对于一些设置了按需加载的库(如ant-design-vue),或者其他一类经常变更的类库,这种就不适合放到dll中。直接打包进入vender可能会导致打包较大,可以利用optimization.splitChunks进行分包配置,该配置是webkpack4.x开始引入,替代了之前的commonsChunkPlugin。
optimization.runtimeChunk,设置true会为每个含有runtime的入口起点添加一个额外的chunk,用于表示模块的依赖关系清单,会增加项目中打包文件的个数,可能会出现文件请求加载时间大于他的执行时间,考虑到该情况,项目中设置了false,取消单独打包。
splitChunks根据cacheGroups进行拆分,cacheGroups可以继承或者重写splitChunks中的属性。但是test,priority和reuseExistingChunk只能在cacheGroups中配置。即使项目中并没有对splitChunks进行配置,splitChunks也是生效的。源于webpack默认会有两个缓存组,vender和default。
参考配置如下:
2.2.3 解决路由懒加载失效问题
路由懒加载是指利用import函数动态导入组件,把不同路由对应的组件分割成不同的代码块,从而达到当路由被访问时才加载对应的组件。
{ path: '/login', name: 'login', component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login') }
该方式在项目中其实已经进行了配置,但是分析项目的过程中,我们发现,路由懒加载的配置并没有生效。排查后发现,在某个组件文件中存在这样一段代码,该逻辑会将views下边所有的文件都打包进去,导致路由懒加载配置失效,还会将无效代码打包进去,增加打包体积。
2.2.4 IgnorePlugin
IgnorePlugin用于忽略指定包的指定目录,使这些目录不被打包。例如直接引入了moment,会打包出冗余的i18n代码,增加打包文件的大小,实际场景中并不需要这些i18n代码,可以采用IgnorePlugin忽略这些文件。
new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ });
2.3 其他
通过chrome的memory面板查看系统的堆内存快照,发现系统存在一定程度的内存泄露,从代码规范层面减少内存泄露。例如:
- $on/$off、addEventListener/removeEventListener、事件处理是否成对出现
- 是否有未断开连接的观察器MutationObserver/ResizeObserver/IntersectionObserver
- 是否有遗忘的定时器setTimeout/setInterval
- 处理游离的DOM节点
3 优化效果
经过一系列的优化,打包层面大文件压缩效果比较显著(如图2),系统首屏加载时间提升了大约30%,系统打开速度有了比较大的提升,优化了用户体验。
图2 优化后打包图
写在最后:
打包优化过程中,希望monaco包拆分出来,但是没有成功。若是有遇过该问题的同学,可以一起探讨探讨。