webpack 性能优化

103 阅读3分钟

我正在参加「掘金·启航计划」

webpack 性能优化

对于 webpack 性能优化,相信每个同学都对“打包”和“压缩”这样的事情烂熟于心,掘金也有很多相关的写得很优秀的文章。对于常见主要是以下几个方面:

  • 压缩打包的结果体积

  • 动态加载,减少首屏资源加载量

  • 减少构建过程时间

  • 优化 HTTP 资源缓存效率



压缩打包的结果体积

Webpack 的压缩代码能力,相信每个同学都见识过,甚至还把压缩成果放在了简历上:“webpack 打包后体积从 5** kb 降到 2** kb ,相比优化前节省了 38%  的代码体积”。那 webpack 是如何做到在保持一致的代码逻辑、执行流程、功能效果下,节省代码体积呢。

接下来我们从一个例子出发,假设现在有一段代码:

企业微信截图_1677469647573.png

变量名 WEBPACK 语义很明确,看到就基本明白是干什么用的,但这对计算机并没有什么意义,我们完全可以将 WEBPACK 修改为 a —— 从 7 个字符精简为 1 个字符,但仍保持改动前后逻辑、功能效果完全一致。并且可以看到 =+ 的两边都有空格,完全可以将这前后两个空格删掉。

然后继续观察代码

企业微信截图_1677470032533.png

发现 abc 都是 const 常量,意思是他的值被设置以后就不能修改了,这就说明 c=a+b 也是个常量,那可以把它再压缩一下:

企业微信截图_16774703899018.png

通过上面简单的代码压缩,已经把原来的 93 个字符压缩成 20 个字符,相当于压缩了 78% 的代码体积!

同样的方法也可以对 CSS 或者 HTML 代码进行压缩。



动态加载

动态加载应该是接触最多的优化了,逻辑上,直到页面的时候才会加载当前页面的代码,因此这部分代码没必要出现在首屏资源列表中,此时我们可以使用 Webpack 的动态加载功能将该模块更改为异步导入,相信很多同学在 VUE 项目中都写过类似的代码:

企业微信截图_16774742124581.png

动态加载是 Webpack 内置能力之一,我们不需要做任何额外配置就可以通过动态导入语句(importrequire.ensure)轻易实现。但请注意,这一特性有时候反而会带来一些新的性能问题:一是过度使用会使产物变得过度细碎,产物文件过多,运行时 HTTP 通讯次数也会变多,在 HTTP 1.x 环境下这可能反而会降低网络性能,得不偿失;二是使用时 Webpack 需要在客户端注入一大段用于支持动态加载特性的 Runtime



压缩图片

Webpack4 还没有将 file-loader 内置,所以要写一行 use: ['file-loader']

但是 Webpack5 之后只需要通过 module.rules.type 属性指定 资源类型 即可。

使用 image-webpack-loader 压缩图片,并只作用在正式环境(图像压缩是一种非常耗时的操作)

module.exports = {
  // ...
  module: {
    rules: [{
      test: /\.(gif|png|jpe?g|svg)$/i,
      // type 属性适用于 Webpack5,旧版本可使用 file-loader
      type: "asset/resource",
      use: [{
        loader: 'image-webpack-loader',
        options: {
          // jpeg 压缩配置
          mozjpeg: {
            quality: 80
          },
          // 在生产环境下开启
          disable: process.env.NODE_ENV === 'development'
        }
      }]
    }],
  },
};


持久化缓存

持久化缓存是 Webpack5 才更新的,它能够将首次构建的过程与结果数据持久化保存到本地文件系统,在下次执行构建时跳过解析、链接、编译等一系列非常消耗性能的操作。

  • cache.type:缓存类型,支持 'memory' | 'filesystem',需要设置为 filesystem 才能开启持久缓存;
  • cache.cacheDirectory:缓存文件路径,默认为 node_modules/.cache/webpack ;
  • cache.buildDependencies:额外的依赖文件,当这些文件内容发生变化时,缓存会完全失效而执行完整的编译构建,通常可设置为各种配置文件


将 Loader 用在刀刃上

loader 设置 includeexclude,避免不必要的转译

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader", "eslint-loader"],
      },
    ],
  },
};


参考资料:

Webpack5 核心原理与应用实践
github.com/tcoopman/im…