实战剖析-vue项目首屏加载时长优化

现状分析:

首屏速度是用户体验的最关键一环,而首屏速度最大的决定性因素就是资源的加载速度,资源加载速度等于资源大小 + 网速,老的前端项目随着不断增长,代码可能会变得混乱,冗余难以理解,不断的做加法,久而久之,前端性能上就会受到影响,相信大家在工作当中一定遇到,页面加载时间慢,响应时间长等问题,本文将以具体项目为例(vue 2.51.7 webpack:4.23.1),一点一点分析,通过实战的角度,介绍如何对Vue项目的首屏加载时间进行优化。

首先我们分析一下页面加载时间的构成:

(1)资源加载;

(2)代码执行;

(3)页面绘制;

打开chrome开发者模式面板,为了更好的还原用户的使用场景,我在设置-节流配置中添加模拟5G的性能分析选项,对网络状况做最大限度还原,开始录制页面加载过程,

通过性能分析工具,我们就能看到一共有哪些执行,花了多长时间,通过查看网络面板,可以查看到每一个资源的加载时间,脚本执行,页面渲染和绘制时间,可以看出等待加载资源过大,执行脚本时长是占据白屏时间的首要因素。也可利用window.performance,以数据化的形式查看页面的各种时间,甚至可以把这些时间指标通过接口的形式发送给服务端,可以监控我们的项目在用户的终端设备中的表现;

javascript 复制代码
window.onload = function(){
    axios({
        url: "xxx",
        data: window.perfoformace
    })
}


问题找到了,就解决它

针对资源加载太慢的问题我先寻找大佬赏赐了一些思路:

1、找到是哪个文件过大导致,是否可以拆包;2、如果不是马上需要的资源,可以异步加载;3、利用tree-shaking,尽量使用按需引入;4、定期实效数据可以缓存在cookies/localstorage中;5、进行gzip压缩;6、利用webpack / vite对代码进行压缩;

作为一只资深笨鸟,对大佬的思路领悟只有一二成,用最笨的方法,一条一条排查😬

为了直观的发现文件打包体积问题,可以查看打包时生成的报告,有两种方式:通过命令行参数的形式生成报告,也通过可视化的 UI 面板直接查看报告, npm run build --report的命令就可以生成报告,如图所示:在加上 --report命令后,可以生成 report.html来帮助分析包的内容,通过 http://127.0.0.1:8888/ 就可以查看打包报告里面的内容了 ,如图所示:

通过面板分析,app.js压缩后有960kb,发现nutui占据主包体积过大,pinyin.js文件重复多次引入,lodash需要实现按需引入等问题。。。

一、大文件拆包压缩

  • 首先将索引文件通过cdn的方式引入,避免多模块重复引入问题,其次对nutui模块优化,不是首屏加载必须的模块可以按需引入,有一点我们需要注意在对nuti实现外部引入的时候,需要先对vue进行一个引入,因为如果不先引入vue,他就会在console里面报一个错误,原因与elementUI外部引入问题相同,采用cdn的方式引入后,我发现unpkg cnd负优化压缩比gzip还慢,参考大佬建议后,还是决定使用按需引入方式优化。

  • 其次lodashi默认是全包引入的

javascript 复制代码
//全包引入
import { cloneDeep } from "lodash"; 

//只引入cloneDeep函数
import cloneDeep from "lodash/cloneDeep";

通过--report参数 找到具体引入文件,发现尽管只用到了lodash的一个函数,但打包的体积也有几百k,应该就是整包打的,没有按需打包,按照上述方式修改为按需打包,减少包体积,之后需要在.babelrc里做一些配置,安装 npm install babel-plugin-lodash 插件,设置plugins: ["lodash"]参数,之后打包文件就是按需打包的形式了。

  • 说到神兵利器,不得不推荐 tinify.cn/ 图片无损压缩工具,由于平时习惯直接从UI站点下载配图,对图片体积不是很敏感,它可以一次性导入批量无损压缩,一波操作下来,img资源从1.3M变成649K,着实很香。🤓

二、异步引入

目前来说比较新的脚手架版本,它生成的项目里面用到的一种prefetch 加载方案,简单介绍一下这种方案,假设有page1 page2 page3三个页面,1和2是同步加载的,3是异步加载的,那么异步加载的page3就会从app.js中单独拆出来作为一个文件模块,首页马上需要加载的文件都会放到app.js里,vendor.js里面就是page1和page2需要用到第三方库,page3中用到的第三方库就会标记一个perfecth,它都会在首屏打开的时候创建link标签去加载,有这个标记的资源会进入队列等待加载。

Vue 2.5.17 版本本身并不直接支持 prefetch 加载,然而,2.x 版本支持异步组件,这可以在某种程度上实现类似 prefetch 的行为,通过动态导入组件来按需加载。例如,可以使用 webpack 的 require.ensure 语法或者 import() 函数来异步加载组件。

javascript 复制代码
components: {
..//
  InsCalc: () => import('@/components/insCalc/insCalc')
..//
}

三、按需引入

  • 现在的打包工具都有一个神兵利器叫做tree-shaking,可以把我们那些第三方库中只用到了的方法打包进去,但是很多库的老版本是不支持tree-shaking,比如我引入的xlsx的用来渲染excel表格,老的版本0.11.2的版本就不支持,我只使用 XLSX.utils.encode_cell / XLSX.utils.encode_range 的方法,打包的代码在压缩前体积就有七百kb,时间怎么也得延长几毫秒吧,升级到0.18之后就可以支持tree-shaking,一般情况下只要支持 import { utils } from "XLSX",都可以利用tree-shaking实现按需引入,这时候打包体积就变成了90kb了。👋

这一系列优化操作下来,再次通过分析工具,app.js主包文件已经有500kb了,虽然不算小,但也有进步了😝 ,加载时长已经变成了4秒左右了。

四、数据缓存

  • 项目中有通过路由拦截的方式实现对用户授权数据进行分析的逻辑,这会直接导致在微信环境下二次跳转到微信生态获取code,由于网络或设备等因素有的用户可能出现三次刷新的情况
javascript 复制代码
beforeRouteEnter(to, from, next) {
 if (//非微信环境) {
   next();
   return;
 }
 const code = to.query.code;
 if (!code) {
     const redirectUrl = `https://jlkauth.jd.com/view?xxxx`;
     const url = `https://open.weixin.qq.com/connect/oauth2/xxxxxx`;
     
 } else {
 //then 逻辑后才next() }
 },

这个问题不解决,再多的优化都没有用,二次刷新的问题可能直接逼退一部分用户,于是开始着手改实现方案,第一步通过原生js实现内部依赖的功能(axios,路由取参,环境判断等...),脱离对项目中npm包的依赖,鉴于多个项目都在使用这个功能,采用cdn文件引入的方式,统一管理,项目内采用对构造函数的实例进行传参的方式,在index.html中引入,可以在最早的加载时机触发换code的逻辑,减短白屏等待时间,第二步通过对已授权用户的数据缓存,避免刷新页面请求,最大程度的降低了授权操作带来的耗时影响。

xml 复制代码
<script src="https://cdn.../js/wxShareTrack.js"></script>
<script>
 const wxTrack = new WxShareTrack();
 const visit = {
     visitTitle: '标题信息',
     visitType: '类型'
};
 wxTrack.wechatTrajectoryReport(visit);
../
</script>
  • 第五点和第六点一般我们不会有什么工作量,利用nginx访问资源的时候,一般都是会开启压缩的,利用webpakc或vite对代码进行压缩,也是我们利用npm打包的时候,自动进行压缩的,可以在chrome的network面板中的Content-Encoding这一栏中看到是否开启gizp压缩。

结尾

总的来说,性能优化是一个涵盖多个层面的综合性概念,对于不同业务场景下的前端项目而言,适用的方法也各不相同,上述的各种优化措施,是通过分析实际情况,定位性能瓶颈,并选取的适合的优化策略,感谢阅读😘

相关推荐
一个处女座的程序猿O(∩_∩)O2 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink5 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者6 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-7 小时前
验证码机制
前端·后端
燃先生._.8 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖9 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235249 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_7482402510 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar10 小时前
纯前端实现更新检测
开发语言·前端·javascript