通过代码覆盖率减小JS代码体积实践

1. 背景

个人站点访问性能优化,当前核心问题是js脚本体积过大,耗时占比很高。

因此,想通过代码覆盖率工具,抽取出使用到的代码,丢弃未使用代码,减少文件体积,提升访问速度。

从评估的代码覆盖率来看,着实有极大的优化动力。

2. 实践过程

2.1 使用Coverage工具

2.1.1 获得代码覆盖率并导出

打开chrome开发者工具后,按下 ctrl + shift + p,会弹出一个输入框,

输入coverage,点击后在下方可以看到coverage面板:

点击刷新按钮,开始捕获界面操作。

此时就可以开始界面操作,注意要保证每个界面,每个事件都能覆盖到。

如果可能,最好是做到界面操作自动化,因为每次代码编译后会生成新的文件,每次都要操作一次,人工操作总有可能会漏掉一些界面和操作,以致代码覆盖率不准,如果获取到的used代码有遗漏,则访问界面时会出问题。

注意:一定是要用准备发布的文件来操作,否则操作完之后,重新编译,生成新的文件,那就白操作了,当然如果能保证每次编译只是文件名的hash值不同,而文件内容完全一样(代码没有改动过,只是重新编译)也行。

操作完之后,可以查看代码覆盖率:

其中红色是unused,绿色是used,看起来unused的代码还不少,操作之后可以导出文件,文件是json格式,样例如下:

java 复制代码
[
    {
  {
    "url": "https://www.kengcoder.com/assets/index-T1fy7zxz.js",
    "ranges": [
      {
        "start": 0,
        "end": 208
      },
      {
        "start": 331,
        "end": 377
      },
	]
    "text": "(function(){const t=document.createElement(\"link\").relList;...."
  },
]

这个导出文件可以用于抽取used的代码,替换体积较大的原始文件。

2.1.2 json文件格式说明

json格式内容是一个数组,每个数组包含一个文件的代码覆盖率信息,分为如下几部分:

序号 类型
url 文件的url路径
ranges used代码的位置数组,每一个元素包含[start, end],start是起始位置,end是结束位置,所有元素加起来就是所有used的代码
text 每个url指定文件的全量原始代码,可以用来生成新的used代码。

2.2 used代码抽取

初看到这里,可能会觉得so easy,只要遍历ranges数组,按照[start, end]截取代码就行了,如果是我们自己的代码按照统一格式写的可能问题不大,但是三方软件各种写法都有,我们看下实际的used代码块长啥样:

2.2.1 代码覆盖率场景复杂

● 场景1 纯粹的used代码

● 场景2 去掉unused仍然语法正确

● 场景3 去掉unused后语法错误

对于前面两个场景直接根据[start, end]截取没有问题,但是对于场景3就会出现语法错误。

这个时候,我们可能想挑战一下,通过增加特殊的截取逻辑来保证语法正确,不过建议不要有此想法,因为还会出现什么新的语法错误场景,以及是否有规律,无法预测,解决起来会耗费大量时间,比如再看看下面代码:

2.2.2 解决思路

● 给coverage工具开发者提issue

如果真要解决,最正确的办法是给coverage工具开发者提issue,让他们来保证,不会出现一个有效代码块被拆成used和unused两部分的情况。

● 临时方案

如果按照上面所说,问题没解决前是否没办法缩小代码体积了,也不一定,既然used部分搞不定,就看看unused部分是否可以,去掉unused的代码,剩下的当作used代码。

对于上面的场景3,和场景4也包含了unused代码,这部分说了解决不了,所以这些都全部当作used代码。

再分析分析看看哪些是可以安全的当作unused代码的,如下:

这些代码看起来都有共同规律,就是从start位置开始,并且以function开头定义的函数,似乎都能安全删除,类似的还有以setup()开头的。

发现规律后,剩下的就是验证是否可行,以及这种场景能减少的文件体积是否划算,如果因为体积减小能提速25%以上,并且整个过程不是很复杂,还是值得的。

2.2.3 开始验证临时方案

按照以上思路开始验证后,又发生了新的问题,那就是生成的coverage.json文件的起始位置不准确,按照该文件截取代码后无法得到正确代码。

json文件的标注位置:

coverage界面查看到的实际位置:

对于这个bug实在有点难理解,按照界面展现结果导出数据不就可以了么,为啥导出的数据和界面不一致,即便是两个团队开发的,一个负责界面展现,一个负责数据导出,也应该对齐处理逻辑。

对于这个bug,已有人给chromium提过issue,也修改过代码,但实际情况是,最终并未覆盖到所有场景,还是有问题(或许简单的js脚本没有问题,例如都是统一的函数定义,没有嵌套,但那就不得而知了)。

bugs.chromium.org/p/chromium/...

github.com/puppeteer/p...

到了这一步,看起来似乎无解了 !!!

2.2.3 新的解决思路

既然界面的位置是正确的,那就从界面获取代码覆盖率,思路如下:

将光标不断的向下移动,到了红绿或绿红交界的位置时,获取下面的Line和Column信息。

红-绿交界可获得used代码开始位置,绿-红交界可获得unused代码开始位置,最终就可以计算出unused代码段信息。

思路有了,开始操作,手工肯定不行,搞个机器人自动抓取并记录数据,经过一顿操作之后,机器人跑起来.......

原始文件1百万个字符,跑了一晚上大概10个小时,大约完成1/5,这主要是因为获取下面的数据要通过OCR图片识别,比较耗时,快不了。

本来想趁热打铁一晚上跑出结果,立马验证下,现在还要再跑4个晚上,感觉这种方式着实太折腾,对于商业产品绝对不可行。

实在不想再等几个晚上出结果,于是就开始尝试别的办法减小代码体积,最后也达到了目的。

至此,通过代码覆盖率减小JS代码体积的验证就暂时搁置了。

3. 总结

● 本次实践没有死磕得到最终结果也是出于性价比考虑,首先已有其他方法可以达到相同目的,其次当前实践的方式确实折腾了点,且以后每次更新代码还要再折腾,代价着实太大,因此暂时先放弃,万不得已需要时回头再来做验证。

● 非正常手段或许可以解决问题,但很可能费时费力,还极易出错,如果不是万不得已,还是尽量通过正常手段解决。

● 大公司的代码也会有bug,是否解决一样会看性价比,以及是否普遍场景下会出现,上面描述的问题没有得到解决,估计是错误场景没法100%完全覆盖到,因此只能不了了之。


其他阅读:

掘金都使用webp图片提速降本,必须安排!
Spring AOP-AspectJ注解实现拦截
Spring AOP-编码实现拦截
Spring Cache架构、机制及使用
布隆过滤器适配Spring Cache及问题与解决策略
如何编写软件设计文档
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(五)函数式接口-复用,解耦之利刃

相关推荐
梦境之冢23 分钟前
axios 常见的content-type、responseType有哪些?
前端·javascript·http
racerun26 分钟前
vue VueResource & axios
前端·javascript·vue.js
m0_5485147743 分钟前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
AndrewPerfect43 分钟前
xss csrf怎么预防?
前端·xss·csrf
Calm5501 小时前
Vue3:uv-upload图片上传
前端·vue.js
浮游本尊1 小时前
Nginx配置:如何在一个域名下运行两个网站
前端·javascript
m0_748239831 小时前
前端bug调试
前端·bug
m0_748232921 小时前
[项目][boost搜索引擎#4] cpp-httplib使用 log.hpp 前端 测试及总结
前端·搜索引擎
新中地GIS开发老师1 小时前
《Vue进阶教程》(12)ref的实现详细教程
前端·javascript·vue.js·arcgis·前端框架·地理信息科学·地信
m0_748249541 小时前
前端:base64的作用
前端