前言

昨天 lyanna 刚发布了 v3.2,这里面只有一个更新,就是极大的降低了后台和动态这种使用 Vue+webpack 生成的 Javascript 文件的体积。其实代码改动不大,但是效果很明显,本文就是分享这件事。

原来的效果

在之前的版本里面 Javascript 文件大小如下:

❯ du -sh static/js/activity/*.js
208K    static/js/activity/app.js
1.9M    static/js/activity/chunk-vendors.js

❯ du -sh static/js/admin/*.js
824K    static/js/admin/app.js
8.0K    static/js/admin/chunk-2d230fe7.js
4.0K    static/js/admin/chunk-2d2382a4.js
28K static/js/admin/chunk-46e421b1.js
1.9M    static/js/admin/chunk-vendors.js

可以看到 chunk-vendors.js 都达到了 1.9M!,app.js 文件也比较大。

关于上一次优化可以看 优化博客后台 (Vue) Javascript 文件体积 这篇文章,主要是把一些比较大的库抽出来,用 CDN 来独立服务。

当时我的感觉是页面那么点逻辑,即便加上相关依赖也不应该产生这么大的文件,但是由于不了解 webpack 工作原理就先作罢了,不过幸好做过运维,知道可以在 Nginx 上开启 Gzip 压缩,所以大家在访问页面时,请求的文件大小约实际的 1/3:

lyanna 3.0 加了动态后,又看到这样的文件体积问题。虽然 chunk-vendors.js 是 590k 看起来不大,由于网站流量小我倒不考虑带宽问题,但关键是打开慢呀,你想想访问者打开它需要几秒,页面就一直空白着?所以马上加了 CDN 的支持:过去静态文件是直接服务的,现在已经改成了使用某云。缓解了打开慢的问题,不过「文件大」还是没有根本解决。所以昨天我又开始研究这个问题了,下面是过程。

尝试修改依赖关系解决

网站翻了很多优化文件,无果。第一个点是看yarn build --report生成的报告产生的思路,先看一下:

左上有一个很大的 core-js 区域,好像这不是我的依赖啊!查了下,说它是 @babel/polyfill 的核心依赖,打开 package.json 文件看到它在 dependencies 项里面。我来了灵感,因为 dependencies 是生产环境里需要打包的库,而它和 node-sass 以及 sass-loader 等都是打包过程用的,我不记得我为什么没把它放在 devDependencies 项里面。

但是尝试了一下,对产生的 dist 文件体积没有影响,失败~

找到终极优化方案

最终是我用编辑器打开 chunk-vendors.js 文件,想看看里面到底有什么。我翻到了非常非常多的类似下面的内容:

...//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvY29yZS1qcy9pbnRlcm5hbHMvdG8tc3RyaW5nLXRhZy1zdXBwb3J0LmpzPzAwZWUiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsc0JBQXNCLG1CQUFPLENBQUMsTUFBZ0M7O0FBRTlEO0FBQ0E7O0FBRUE7O0FBRUEiLCJmaWxlIjoiMDBlZS5qcyIsInNvdXJjZXNDb250ZW50IjpbInZhciB3ZWxsS25vd25TeW1ib2wgPSByZXF1aXJlKCcuLi9pbnRlcm5hbHMvd2VsbC1rbm93bi1zeW1ib2wnKTtcblxudmFyIFRPX1NUUklOR19UQUcgPSB3ZWxsS25vd25TeW1ib2woJ3RvU3RyaW5nVGFnJyk7XG52YXIgdGVzdCA9IHt9O1xuXG50ZXN0W1RPX1NUUklOR19UQUddID0gJ3onO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmluZyh0ZXN0KSA9PT0gJ1tvYmplY3Qgel0nO1xuIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///00ee\n")}...

整个文件就是因为这种注释造成的文件过大。啊!这不是 sourcemap 嘛?我还是怀疑人生,因为项目一开始我就在 vue.config.js 里面加了一句productionSourceMap: false,表示生产环境禁用... 但是木有生效!或者我理解错了,它只是说生产环境不用 xx.map 文件。

然后搜了下,改成了下面这样:

const debug = process.env.NODE_ENV !== 'production'

module.exports = {
    ...
    productionSourceMap: false,  // 生产环境禁用
    configureWebpack: (config) => {
        if (debug) {
            config.devtool = 'eval-source-map'
        } else {
            config.devtool = false
        }
        config.output.filename = 'static/js/activity/[name].js'
        config.output.chunkFilename = 'static/js/activity/[name].js'
        config.externals = {
            'vue': 'Vue',
            'moment': 'moment'
        }
    },
    ...

主要是 configureWebpack 部分内部加了判断,如果在开发环境使用eval-source-map,生产环境不开启 devtool 这项。

重新yarn build:

❯ du -sh static/js/activity/*.js
28K     static/js/activity/app.js
364K    static/js/activity/chunk-vendors.js

❯ du -sh static/js/admin/*.js
108K    static/js/admin/app.js
4.0K    static/js/admin/chunk-2d230fe7.js
4.0K    static/js/admin/chunk-2d2382a4.js
4.0K    static/js/admin/chunk-45698e1a.js
268K    static/js/admin/chunk-vendors.js

就拿 activity 的文件来说,app.js 从 208k 降到了 28k (原来的 1/7),chunk-vendors.js 从 1.9M 降到了 364k (原来的 1/5)。感觉很多效果都有这个问题啦~

再看看浏览器访问的压缩之后的文件体积:

合并 vendor 和 app

前面已经优化了 chunk-vendors.js,现在 app.js 和 chunk-vendors.js 都不大,没必要产生 2 个请求,所以合并一下:

// vue.config.js
module.exports = {
  configureWebpack: {
    optimization: {
      splitChunks: false
    }
  }
}

再看看:

❯ du -sh static/js/activity/app.js
384K    static/js/activity/app.js

现在体积比之前的 392 (364 + 28) k,还要小一点。

后记

最后表达一下心情: