实战剖析-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压缩。

结尾

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

相关推荐
酷爱码15 分钟前
css中的 vertical-align与line-height作用详解
前端·css
沐土Arvin29 分钟前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
专注VB编程开发20年31 分钟前
VB.NET关于接口实现与简化设计的分析,封装其他类
java·前端·数据库
小妖66640 分钟前
css 中 content: “\e6d0“ 怎么变成图标的?
前端·css
L耀早睡1 小时前
mapreduce打包运行
大数据·前端·spark·mapreduce
HouGISer2 小时前
副业小程序YUERGS,从开发到变现
前端·小程序
outstanding木槿2 小时前
react中安装依赖时的问题 【集合】
前端·javascript·react.js·node.js
霸王蟹2 小时前
React中useState中更新是同步的还是异步的?
前端·javascript·笔记·学习·react.js·前端框架
霸王蟹2 小时前
React Hooks 必须在组件最顶层调用的原因解析
前端·javascript·笔记·学习·react.js
专注VB编程开发20年3 小时前
asp.net IHttpHandler 对分块传输编码的支持,IIs web服务器后端技术
服务器·前端·asp.net