背景

近来,咱们团队开始尝试用新的解决方案(双端开发,同时投放PC端和挪动端)解决前端资源短缺问题。但提测后,测试提出咱们挪动端页面首屏太慢(6s+),体验极差。

我尝试在PC端关上这个页面,耗时4s+,加载瀑布流长上面这样:

粗略一剖析,存在上面三个问题:

  • 利用页面采纳了懒加载策略,详见红色圈注区域;
  • 入口js,包体积太大,gzip之后还有1.3M, 原始大小4M+
  • 日常动态资源未开启cdn

优化三部曲

一、利用架构优化

在利用架构中,懒加载是一个常见的优化技巧,它能够在须要时才加载资源,缩小利用的启动工夫和流量耗费。然而,懒加载并不是万能的,有时候过多的懒加载反而会升高利用性能。因而,在进行利用架构优化时,应该依据具体情况衡量是否采纳懒加载。

依据瀑布流联合上图的剖析,资源的加载用时4s+,index.html 的工夫对于前端来说是不可控的,这齐全取决于域名的解析和服务器的响应。但js 和 css 这一段是齐全可控的,咱们能够把前面 500ms 的资源加载用时提前,也就是去除懒加载的架构计划。

二、包体积优化

包体积优化是优化利用性能的重要一环。包体积的大小间接影响利用的加载工夫和用户体验。

当看到1.3M的gzip包大小后,咱们第一反馈就是去开启webpack的analyse查看包体积散布,后果齐全超出设想(这是development模式,正文了其余页面入口,仅保留了时段菜单一个页面):

下面这张图也很直观的暴露出几个问题:

  • 同一个chunk同一个依赖被屡次打入(以图中的cook-design为首,见下图)
  • 包的大小散布极不平均
  • 不同chunk打入同一版本依赖(懒加载策略造成)

我的项目依赖治理,避免多版本

在我的项目依赖治理中,应该尽可能防止多版本的依赖关系。多版本的依赖关系会导致包体积变大,甚至会产生抵触和谬误。在日常业务组件开发中,对根底组件(比方antd)的依赖,能够设置为peerDependencies。

咱们的解决思路是通过标准业务的依赖引入形式 和 通过resolution 强制指定版本。

组件库反对treeShaking

在应用第三方组件库时,通过treeShaking,能够只加载利用中所需的组件和函数,缩小包体积和加载工夫。以往咱们引入antd3时,为了避免包体积过大,就会引入babel-plugin-import帮忙咱们去除无用代码。但antd4听从es-module标准,并配置了sideEffect,使得人造反对treeShaking。

咱们的我的项目大量依赖了本地生存的 cook-design 与 cook-design/icons,这两个因为短少 treeShaking 配置,导致组件被残缺打了进来,其冗余组件与冗余组件带来的依赖,体积在5M左右。

所以咱们在和相干的维护者交换了相干想法后,其批准加配置降级反对treeShaking,咱们团队本人的双端组件库cook-design-mixin也反对了这个配置。

在优化利用架构、优化依赖的版本、组件反对treeshaking、以及采纳分包策略后,咱们的构建后果(production 模式)长上面这样:

去除无用代码

将利用中的无用代码去除是包体积优化的重要伎俩之一,我在文章结尾提到,咱们这个我的项目是一个双端架构的我的项目, 它是一个编译时计划,这就是意味着pc端和挪动端投放是两套不同的资源。但因为咱们是在一个利用中开发,所以pc端的代码和挪动端的代码是混着写的,咱们通过标准和构建插件来解决代码混写的问题。

// 上面是一个示例import { Decorator } from '@alife/wa-mixin-core';import DMobile from './wa-mobile';import DDesktop from './wa-desktop';export default (props: {  isShowTipStatus: boolean;  showMode?: boolean;}) => {  return Decorator({    Mobile: <DMobile {...props} />,    Desktop: <DDesktop />,  });};

但通过代码剖析,咱们发现上面两个问题:

  • 双端组件库晚期编写的组件存在大量的编写不标准,导致构建插件无奈shaking掉另一端的代码,从而导致挪动端打入了pc端的代码(涉及面太广,后续做专项优化)
  • 业务代码因为是存量业务(这里指菜品下发)转双端(后期pc端代码已开发上线,挪动端采纳双端计划开发),所以导出的不标准,导致包体积剧增

当咱们把菜品下发入口退出时,构建后果长上面这样,比下面单入口的减少2.3M(压缩后的):

而只留下发一个入口,构建后果长上面这样:

上面页面的引入,导致大量的cook-design 与 cook-design/icons被引入,以致于我过后在思考要不要为icon独自拆一个包或者通过cdn引入。

包入口被治理后,构建包大小显著达到了改善:

gzip 之后,大小根本在1M以类(还有改善的空间):

三、网络申请优化

网络申请优化是优化利用性能的另一个重要环节。在进行网络申请优化时,能够思考以下几个方面:

利用combo升高申请数量

在前端利用中,通常须要加载多个JS、CSS、图片等资源文件,这会产生大量的网络申请,影响利用性能。能够应用combo技术,将多个文件合并成一个文件申请,缩小网络申请的数量, 不过这也须要服务器的反对。咱们的利用模版将react、moment、babel-polyfill等应用cdn作为内部依赖引入,但为了缩小申请数,应用了combo服务。

利用http2的多路复用提供申请效率

http2反对多路复用,能够在一个连贯上同时传输多个申请和响应,进步申请效率和传输速度。因而,在应用http2协定时,能够利用多路复用优化网络申请。所以才有了下面分多个包的策略,为了能最大化利用古代网络的带宽。

期待队列优化

在分包依赖实现后,咱们发现js资源包的加载存在显著的期待状况(如上图),而且是稳固复现的,通过剖析,咱们发现脚手架提供的利用html模版,存在同步script引入vconsole,从而阻塞了js资源的下载。

缩小DNS解析 与 TCP的握手工夫

在排查期待队列问题时,咱们还发现,html模版中利用局部内部依赖应用了非团体的cdn域名问题。在http1时代,这个做法是被提倡的,因为浏览器对单个域名同时的http连贯有限度,所以为了减少并行申请数,在同一个网页中,会采纳几个cdn域名。但http2,这个就成了解放,而且采纳内部cdn,会带来平安危险。

在下面的策略全副施行后,日常环境,利用首屏稳固在1.5s左右。待双端组件库按标准调整后,这个数据能再快10%。

开启cdn减速

什么是cdn,置信大家都应该很理解了。在咱们利用上线后,动态资源终于失去了cdn魔法的加持。页面在咱们的投放app掌客端也顺利实现了秒开,体验极好:

总结

首屏优化是前端经久不衰的话题,其伎俩丰盛、细节繁多。利用架构优化、包体积优化和网络申请优化是优化前端利用性能和进步用户体验的关键所在。

本文由ChatGPT拟初稿,打工人加工而成。