webpack5打包性能优化

261 阅读2分钟

本文主要描述针对大型项目,通过调整webpack的一些相关配置提升打包性能,由于项目体积较大处理内容多耗时很长,针对一些配置调整可以起到优化打包性能的效果。

从本质上讲,webpack是现代 JavaScript 应用程序的静态模块打包器。 当 webpack 处理您的应用程序时,它会在内部从一个或多个入口点构建一个依赖关系图,然后将您项目所需的每个模块组合成一个或多个bundles,这些 bundles 是用于提供内容的静态资产。

include和exclude缩小搜索文件范围

默认情况下webpack根据配置中的Entry开始递归解析文件的导入语句,webpack首先根据导入语句找到对应文件,再通过导入文件的后缀采用配置的loader处理文件。

可以通过缩小处理文件的范围排除不需要处理的文件或者指定只处理某一部分文件减少耗时,比如大部分情况下不需要babel处理的node_modules文件。

exclude决定当前loader不需要处理哪些文件;
include决定当前loader需要处理哪些文件;
{
        test: /\.m?js$/,
        exclude: /(node_modules)/,
}

注:exclude优先级高于include

持久化缓存

webpack5新增了缓存配置,在首次构建后webpack会生成相应的缓存文件,下次构建时会跳过解析依赖等耗时操作,提升打包的速度和性能。

默认未开启需要手动设置

module.exports = {
  cache: {
    type: 'filesystem',
  },
};

这是没有开启缓存的耗时: image.png

开启缓存后第一次耗时和没有开启缓存时差不多,但之后的打包耗时被缩短到仅660ms,相比没有开启缓存有质的提升。

image.png

原理

由于webpack每次构建时需要调用loader加载文件、生成遍历AST、代码转换等大量耗时操作;开启缓存后webpack可以将构建结果缓存到磁盘中,在下一次构建时webpack会尝试读取缓存并对比文件内容的哈希决定是否使用缓存文件,对发生变更的模块则进行重新编译构建。

image.png

在开启缓存后webpack默认会在node_modules下生成.cache文件

也可以通过配置自定义缓存文件位置

cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.temp_cache'),
  },

由于webpack4本身是不具有持久化缓存功能的,不过可以针对babel等耗时的loader可以单独配置他们的cache。

针对babel可以单独开启缓存配置,相应的会在node_modules下生成cache:

use: {
  loader: 'babel-loader',
  options: {
    cacheDirectory: true,
  }
}

oneOf

通过oneOf设置使文件只被其中一个loader命中处理,默认情况下一个文件需要通过所有的loader判断是否需要被处理,针对规则匹配时仅使用第一个匹配规则,可以减少相应的筛选。

在项目中使用的loader较多的时候可以显著提高打包的性能。

rules:[
      {
        oneOf: [
          {
            test: /\.css$/i,
            use: ["style-loader", "css-loader"],
          },
          {
            test: /\.m?js$/,
            exclude: /(node_modules)/,
            use: {
              loader: 'babel-loader',
            }
          }
        ]
      }
    ]

sourceMap配置

根据官网中列出的选项,不同的sourceMap配置对整体的打包速度影响依次是

fastest >> fast >> ok >> slow >> slowest

针对实际使用情况可以调整响应的sourceMap级别平衡内容和打包性能。

不开启sourceMap时构建耗时 image.png

开启sourceMap后 devtool: 'source-map'

image.png

随着项目体积增大和内容增多,对应打包消耗性能也会变的更大;一般开发环境下我们只需要选择eval-cheap-source-map或者eval-cheap-module-source-map模式即可,两者均可映射到具体代码的行号,区别在于前者显示的是经过loader编译后的代码,后者显示的是编译前的源码。