一千零一个优化-0002-vue webpack打包分析

问题继续

“还没发现我?”一个阴暗的角落,一个悄悄咪咪的声音伴随着尖尖的讥笑声传递了开来...一个激灵,小树醒了过来,原来是噩梦。难得午休了一次居然做了一个噩梦,小树心说,显然他还没有缓过神来。去厕所洗了把脸,回到座位上。“滴滴~”,突然一个熟悉的H哥头像在办公聊天工具中闪了起来,消息那头说到,“大佬,上周好了没两天,这礼拜又感觉很慢了,系统使用起来很煎熬啊”,还不忘贴了个图。小树看着图片,心里也是一震,什么情况一个前端文件有3.6m,加载时间总共用了55秒。这个平台还能用?完全就是用户群体人美心善,不然小树早就拜拜了。顶着巨大的压力,小树还是用十分平静的语气回了一句,“本周内我把这个大文件压缩到1.5m以内,加载速度至少提升一倍”,虽然此刻心里还是很忐忑。H哥只是象征性的回了一句,谢谢大佬,然后就没了声响。

怎么做

完全没有方向,虽然也是写了段时间vue的人了,使用webpack打包也用了很多次了,但是真要说如何去优化打包逻辑,把公共模块包从原来的3.6m压缩到1.5m,小树心里是真没有多少头绪。

作为一个老职场人,小树深知团队的力量大无穷,目光迅速锁定了公司的前端大佬J哥。于是小树就向J哥描述了下诉求,J哥轻快的答应了协助一起进行优化,经过大约3分钟的前端架构情况,J哥突然两眼放光,思绪如潮,唰唰唰,给出了一个方案。在前端中很多时候,会走cdn,比如很多公共依赖比较大的,不需要每次都用webpack 打进common-chunk里面,可以用外部引用的方式进行替换,这样一个是减小基础包的大小,又能减轻客户端服务器的压力,还能增加用户的体验(公共部分可以直接通过缓存获取,不用每次构建都重新下载一次)。

迅速的,使用html-webpack-plugin,就把一些比较大的公用库直接外部引用(asserts)。终于功夫不负有心人,小树的第一次构建开始了。结果出来从3.6m压缩到了2.43m,任务完成度50%。2.43m的公共包的实际加载体感,基于小树公司的网络环境的特殊性,结果还是很不稳定,有所提升但是体感不明显。仔细想想其实是因为,虽然用了外部依赖,但是第一次全新加载的时候,整个基础包还是没有缩小的,只是被分割成多份了而已。于是继续找J哥,方案多少有点效果,J哥因为业务项目忙的不可开交,占线情况严重,小树只能自己想想办法了。

还能怎么做

度娘,科学谷歌双管齐下,如何优化前端打包逻辑,是否当前打包的依赖中存在不合理性,是否有工具可以分析打包的力度和效果,有没有webpack插件可以进一步压缩打包结果,只见小树的搜索栏飞速的运作着。

终于功夫不负有心人,让小树查到了点东西,可以使用一个插件分析打包详情。webpack-bundle-analyzer,通过该插件,可以有一个打包结果分析图从而了解实际的组成,而且操作比较简单。

// vue.config.js, 需要npm install webpack-bundle-analyzer 添加插件依赖
...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
...
 plugins:  [
      new BundleAnalyzerPlugin(
        {
                  analyzerMode: 'server',
                  analyzerHost: '127.0.0.1',
                  analyzerPort: 8888,
                  reportFilename: 'report.html',
                  defaultSizes: 'parsed',
                  openAnalyzer: true,
                  generateStatsFile: false,
                  statsFilename: 'stats.json',
                  statsOptions: null,
                  logLevel: 'info'
                    }
           )]
...
// package.json
...
"scripts":{
...
    "analyz": "NODE_ENV=production npm_config_report=true npm run build"
...
}
...

// 执行后页面 127.0.0.1:8888 会自动打开
npm run analyz

image.png

这个包通过压缩以后,其实仔细看下就能发现问题。单单一个brace的依赖压缩后,还需要1.22m。好奇这个brace到底是干嘛的。

image.png 通过继续的内容检索,最后锁定了目标。主要是因为vue2-ace-editor。这是一个富文本编辑工具,有比较强大的语言支持库,而ace-editor主要使用的就是brace库的能力进行各种语言的支持。在平台上主要是用这个组件来让用户添加自定义脚本的例如java和groovy等,但通过对平台的了解,其实不需要支持那么全的语言库,如果只依赖平台需要的brace能力部分,这个brace包的依赖肯定能减少的吧,小树大胆猜测。于是小树就扒起了代码找找哪里有这部分brace内容的引用。最后在如下代码中找到了brace引用片段。

//Edit.vue
...
editorInit: function (editor) {
          require('brace/ext/language_tools') //language extension prerequsite...
          this.modes.forEach(mode => {
            require('brace/mode/' + mode); //language
          });
          require('brace/theme/' + this.theme)
          require('brace/snippets/javascript') //snippet
          if (this.readOnly) {
            editor.setReadOnly(true);
          }
          if (this.init) {
            this.init(editor);
          }
        },
...

看起来,本身平台也有按需加载,那为什么最后,还是加载了全部brace资源呢?转念一想,会不会是因为动态拼接的写法webpack不能精确定位,类似于代码方式的动态引用,必须要先全部加载完以后,才可以支持。如果是全限定名直接引用的话,那webpack应该可以精确定位并按需进行打包了。于是小树就直接用实践来说话,把这部分代码改成了

...
 editorInit: function (editor) {
          require('brace/ext/language_tools') //language extension prerequsite...
          require('brace/mode/java')
          require('brace/mode/javascript')
          require('brace/mode/python')
          require('brace/mode/text')
          require('brace/mode/json')
          require('brace/mode/xml')
          require('brace/mode/html')
          require('brace/mode/sql')
          require('brace/theme/chrome')
          require('brace/theme/eclipse')
          // this.modes.forEach(mode => {
          //   require('brace/mode/' + mode); //language
          // });
          // require('brace/theme/' + this.theme)
          require('brace/snippets/javascript') //snippet
          if (this.readOnly) {
            editor.setReadOnly(true);
          }
          if (this.init) {
            this.init(editor);
          }
        },
...

随后重新用之前的打包分析插件再跑了下结果。

image.png 包体大小直接从2.43m变成了1.44m,直接完成了压缩任务的目标,看到这小树也是松了一口气,再继续搜索相关文件的同时,小树发现了,曾经有人确实发过帖子说brace库在添加引用代码的时候不能使用拼接。相同的问题不只一个人会遇到啊。

小树原想去平台的开源库上也提交个pr,帮助开源社区也做点事情。结果上github一看,就在同一周里,开源库也进行了该问题的优化,从原先的方式改成了和小树自己一样的方式。小树只能淡淡一笑,关掉了github,心想,看来自己的思路已经跟上了大团队的方向。

故事的最后

小树在当天夜里直接上线了最新的调整,并和H哥说明了更新情况,第二天的反馈,H哥也肯定了小树的改造。

后面还会有怎样的挑战,小树此刻不清楚,到现在为止每次都是正面刚问题,小树心中莫名的有些担忧...

猜你喜欢

转载自juejin.im/post/7253371343751446588