One thousand and one optimization-0002-vue webpack packaging analysis

problem continues

"Haven't you found me yet?" From a dark corner, a quiet voice came along with sharp sneers... With a jolt, Xiaoshu woke up, it turned out to be a nightmare. It was a rare lunch break and actually had a nightmare, Xiao Shuxin said, obviously he has not recovered yet. I went to the toilet to wash my face and returned to my seat. "dropdropDit~", suddenly a familiar profile picture of Brother H flashed in the office chat tool, and the message said, "Boss, it's only been two days since last week, and this week feels very slow again, the system is very slow to use. Suffering”, and I didn’t forget to post a picture. Xiao Shu looked at the picture, and his heart was shocked. What’s the situation, a front-end file is 3.6m, and it took a total of 55 seconds to load. Is this platform still usable? It’s all about the user group People are beautiful and kind, otherwise Xiaoshu would have said goodbye long ago. Under the tremendous pressure, Xiaoshu replied in a very calm tone, "I will compress this large file to within 1.5m within this week, and the loading speed will at least increase Double", although I was still very nervous at the moment. Brother H just replied symbolically, thank you, big brother, and then there was no sound.

How to do it

There is no direction at all. Although I have been writing vue for a while, I have used webpack many times for packaging, but I really want to talk about how to optimize the packaging logic and compress the public module package from the original 3.6m to 1.5m. The tree really didn't have much idea.

As a veteran in the workplace, Xiaoshu knew very well the power of the team, so he quickly locked his eyes on Brother J, the front-end leader of the company. So Xiaoshu described the appeal to Brother J, and Brother J briskly agreed to assist in the optimization together. After about 3 minutes of front-end architecture, Brother J's eyes suddenly lit up, his thoughts were flooded, and he gave made a plan. Many times in the front end, CDN will be used. For example, many public dependencies are relatively large. It is not necessary to use webpack to enter the common-chunk every time. It can be replaced by external references. This is to reduce the size of the basic package. , which can reduce the pressure on the client server and increase the user experience (the public part can be obtained directly through the cache, without having to re-download it every time you build it).

Quickly, using html-webpack-plugin, some relatively large public libraries are directly externally referenced (asserts). Finally, hard work paid off, and the first construction of Xiaoshu began. As a result, it was compressed from 3.6m to 2.43m, and the task completion rate was 50%. The actual loading of the 2.43m public package is based on the particularity of the network environment of Xiaoshu Company. The result is still very unstable. It has improved but the body feeling is not obvious. Thinking about it carefully is actually because, although external dependencies are used, the entire basic package is not shrunk when it is newly loaded for the first time, it is just divided into multiple parts. So I continued to look for Brother J, and the plan was more or less effective. Brother J was very busy with business projects, and the line was seriously busy, so Xiaoshu had to figure out a solution by himself.

what else to do

Du Niang, science and Google have a two-pronged approach, how to optimize the front-end packaging logic, whether there is irrationality in the current packaging dependencies, whether there are tools that can analyze the strength and effect of packaging, and whether there is a webpack plug-in that can further compress the packaging results. The search bar is working rapidly.

Finally, the hard work paid off, and Xiaoshu found something. A plug-in can be used to analyze the packaging details. webpack-bundle-analyzer, through this plug-in, you can have a package result analysis graph to understand the actual composition, and the operation is relatively simple.

// 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

After this package is compressed, you can actually find the problem if you look carefully. After the dependency of a single brace is compressed, it still needs 1.22m. Curious what this brace is for.

image.pngThrough continuous content retrieval, the target is finally locked. Mainly because of vue2-ace-editor. This is a rich text editing tool with a relatively powerful language support library, and ace-editor mainly uses the ability of the brace library to support various languages. On the platform, this component is mainly used to allow users to add custom scripts such as java and groovy, etc., but through the understanding of the platform, it does not need to support such a complete language library. If you only rely on the brace capability required by the platform, this The dependence of the brace package can definitely be reduced, Xiaoshu boldly guesses. So Xiaoshu picked up the code to find where there is a reference to this part of the brace content. Finally, the brace reference fragment is found in the following code.

//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哥也肯定了小树的改造。

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

Guess you like

Origin juejin.im/post/7253371343751446588