Webpack 默认的优化措施对于一些小项目来说已经足够了。但是当项目的规模逐渐变大,Webpack 会逐渐产生性能问题,我们需要设置一些优化措施来优化 Webpack 的性能。

找到待优化的地方

前面说到,Webpack 输出的统计数据(stats)里面包含了各阶段的构建信息,我们可以分析 stats 数据来找出性能较差的地方。webpack.debug.ProfilingPluginopen in new windowcpuprofile-webpack-pluginopen in new window 可以将插件的运行时间输出到文件中,然后将这个文件导入到 Chrome 的开发工具中,我们可以看到由此生成的火焰图数据。

一些优化措施

默认情况下,Webpack 只会开启一个实例,无法充分利用多核 CPU 的优势。我们可以通过 thread-loaderopen in new window 或者 parallel-webpackopen in new window 来开启并行模式。parallel-webpack 支持传入一组配置文件,然后并行的进行构建输出。

除了启动多个进程并行构建以外,还有一些细节问题也可以优化。

  • 在开发阶段使用性能更好的 source-map 选项,或者不使用 source-map.
  • 使用 @babel/preset-envopen in new window 来减少现代浏览器中的代码转译。
  • 在开发阶段跳过 polyfill。因为引入 core-js 会极大的增加构建开销。
  • 不对 NodeJS 相关的功能做 polyfill. 比如 polyfill process 对象对构建 bundle 的大小影响很大。
  • 从 Webpack 5 开始,可以通过 cache.type = "filesystem" 来开启文件系统级别的缓存。通过 cache.buildDependencies.config = [__filename] 可以在配置文件发生变化的时候让缓存失效。

除了上面的优化措施,还有一些 loader 级别的优化。

  • 在开发阶段,可以跳过某些 loader。比如对于现代浏览器,我们可以跳过 babel-loader
  • 可以通过 includeexclude 来控制文件检索范围。
  • 可以通过 thread-loader 来讲一些高耗时的 loader 并行执行。

在开发阶段,我们还可以优化重新构建的时间。比如,在 React 项目中,我们可以舍弃 propType,只加载一个 .min.js 版本的 React。结合 module.noParseresolve.alias,我们可以告诉 Webpack 在构建时不处理已经最小化压缩的文件。

exports.dontParse = ({ name, path }) => ({
  module: { noParse: [new RegExp(path)] },
  resolve: { alias: { [name]: path } },
});
1
2
3
4

使用如下:

dontParse({
  name: "react",
  path: path.resolve(
    __dirname, "node_modules/react/cjs/react.production.min.js",
  ),
}),
1
2
3
4
5
6

如此配置,Webpack 在构建时将不会再解析 React 的代码。

总结

我们可以通过多种方式来优化 Webpack 的性能。通常情况下,我们可以从最容易实施的优化措施开始。

我们可以通过并行执行的方式,开启多个实例构建,优化构建性能。

针对现代游览器,在开发阶段,我们可以跳过很多转译 loader 的处理。

关注微信公众号,获取最新推送~