JS `Webpack 5 Persistent Caching`:二次构建速度的极致提升

各位靓仔靓女们,晚上好!我是今晚的特邀讲师,专门来跟大家聊聊Webpack 5的持久化缓存,保证让你的二次构建速度像坐火箭一样嗖嗖地!

开场白:Webpack构建的那些痛

相信各位都深受Webpack构建速度的困扰吧?特别是项目越来越大,修改一小段代码,就要等Webpack吭哧吭哧地编译半天,简直让人抓狂!尤其是当你信心满满地准备提交代码的时候,结果发现Lint报错,然后又得重新构建,那种感觉,就像便秘一样难受!

Webpack构建慢,主要原因就是每次构建都要重新分析、转换、打包所有的模块。如果能把那些没变过的模块缓存起来,下次直接用,那速度肯定能提升一大截!

Webpack 5 持久化缓存:救星来了!

Webpack 5 引入了持久化缓存,就是为了解决这个问题。简单来说,它会把构建过程中的各种信息(模块、chunk、依赖关系等等)都缓存到磁盘上。下次构建的时候,Webpack会先检查这些信息有没有变化,如果没变,就直接从缓存里读取,避免重复劳动。

持久化缓存的原理:简单粗暴但有效

Webpack 5的持久化缓存,就像一个聪明的图书管理员。第一次构建时,它会把所有的模块都整理好,贴上标签(记录hash值),然后放到书架上(磁盘缓存)。下次构建的时候,它会先看看哪些书(模块)没变,直接从书架上拿出来用,那些变了的书才需要重新整理。

配置持久化缓存:简单几步搞定

配置Webpack 5的持久化缓存非常简单,只需要在webpack.config.js文件中添加几行代码:

const path = require('path');

module.exports = {
  mode: 'production', // 或者 'development',建议生产环境和开发环境都开启
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  cache: {
    type: 'filesystem', // 使用文件系统缓存
    cacheDirectory: path.resolve(__dirname, '.webpack_cache'), // 缓存目录
    buildDependencies: { // 依赖项
      config: [__filename], // 当构建配置文件发生变化时,缓存失效
      // 还可以添加其他依赖项,例如:
      // tsConfig: path.resolve(__dirname, 'tsconfig.json'),
    },
  },
};

代码解释:

  • cache.type: 'filesystem':指定使用文件系统缓存。
  • cache.cacheDirectory: 指定缓存的目录,可以自定义,建议放在项目根目录下。
  • cache.buildDependencies.config: [__filename]:这是一个很重要的配置,它告诉Webpack,当Webpack配置文件(webpack.config.js)发生变化时,缓存就失效。因为Webpack的配置可能会影响构建结果,所以要确保配置改变后,缓存也能及时更新。

更细致的配置:提升缓存命中率

上面的配置是最简单的,如果想要提升缓存命中率,还可以进行更细致的配置:

const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.webpack_cache'),
    buildDependencies: {
      config: [__filename],
    },
    // 缓存压缩器和转换器的结果
    managedPaths: [path.resolve(__dirname, 'node_modules')], // 告诉webpack去管理这些路径下的文件
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // 使用多进程并行压缩
        terserOptions: {
          // https://github.com/terser/terser#minify-options
        },
        cache: true, // 缓存压缩结果 (deprecated in webpack 5. use cache.managedPaths instead)
      }),
    ],
  },
};

代码解释:

  • cache.managedPaths: 这个选项告诉Webpack哪些路径下的文件是由包管理器(如npm或yarn)管理的。Webpack会更智能地处理这些文件,提高缓存的命中率。通常,我们会把node_modules目录添加到managedPaths中。
  • optimization.minimizer[].cache: true: 这个选项用于缓存压缩器(如TerserPlugin)的结果。在Webpack 4中,这个选项是有效的,但在Webpack 5中,官方推荐使用cache.managedPaths来管理缓存。

各种缓存策略:选择适合你的方案

Webpack 5提供了多种缓存策略,可以根据你的项目需求选择:

缓存类型 说明 适用场景
memory 将缓存存储在内存中。速度最快,但是当Webpack进程关闭时,缓存会丢失。 适用于小型项目,或者只需要在当前Webpack进程中缓存的情况。
filesystem 将缓存存储在文件系统中。速度比内存缓存慢,但是缓存可以持久化保存,即使Webpack进程关闭,下次启动时仍然可以使用。 适用于大型项目,或者需要在多个Webpack进程之间共享缓存的情况。
构建快照缓存 构建快照会保存有关模块依赖项、文件系统状态和配置的信息。通过创建这些快照,Webpack 可以确定自上次构建以来哪些模块已更改,并只重新构建那些模块。这可以显著加快构建过程,尤其是在大型项目中。构建快照缓存可以与文件系统缓存结合使用,以获得最佳性能。 适用于任何规模的项目,特别是那些具有大量模块依赖项或频繁文件系统更改的项目。

最佳实践:让缓存发挥最大威力

  • 保持依赖稳定: 尽量减少package.json中依赖的版本更新,因为依赖更新会导致大量的模块失效,降低缓存命中率。
  • 合理使用cache.buildDependencies 确保cache.buildDependencies中包含了所有影响构建结果的文件,例如tsconfig.json.babelrc等等。
  • 定期清理缓存: 如果发现缓存占用的磁盘空间过大,或者构建出现异常,可以手动清理缓存目录。
  • 使用stats.json分析构建过程: Webpack可以生成stats.json文件,用于分析构建过程,找出构建瓶颈,从而优化缓存策略。

代码示例:生成stats.json文件

webpack.config.js中添加以下配置:

module.exports = {
  // ... 其他配置
  plugins: [
    // ... 其他插件
    new (require('webpack').WebpackStatsPlugin)('stats.json')
  ],
};

然后运行Webpack构建命令:

webpack --profile --json > stats.json

生成stats.json文件后,可以使用Webpack提供的分析工具webpack-bundle-analyzer来分析构建结果:

npm install -g webpack-bundle-analyzer
webpack-bundle-analyzer stats.json

疑难解答:常见问题及解决方案

  • 缓存没有生效?
    • 检查cache.type是否设置为filesystem
    • 检查cache.cacheDirectory目录是否存在,以及是否有读写权限。
    • 检查cache.buildDependencies是否包含了所有影响构建结果的文件。
    • 尝试清理缓存目录,重新构建。
  • 缓存占用磁盘空间过大?
    • 定期清理缓存目录。
    • 优化构建配置,减少需要缓存的模块数量。
    • 考虑使用更小的缓存目录,例如放在内存盘上(仅适用于开发环境)。
  • 构建速度没有明显提升?
    • 使用stats.json分析构建过程,找出构建瓶颈。
    • 检查是否有很多模块频繁变化,导致缓存失效。
    • 优化构建配置,减少模块之间的依赖关系。

高级技巧:定制缓存行为

Webpack 5 还允许你更精细地控制缓存行为,例如:

  • 自定义缓存键: 你可以使用cache.cacheUnaffectedcache.cacheAffected来自定义缓存键,从而更精确地控制哪些模块会被缓存。
  • 使用自定义缓存加载器: 你可以编写自定义的缓存加载器,来实现更复杂的缓存逻辑。

这些高级技巧需要更深入的Webpack知识,可以根据你的实际需求进行探索。

总结:让Webpack构建不再是噩梦

Webpack 5的持久化缓存是一个强大的工具,可以显著提升二次构建速度,让你的开发体验更加流畅。只需要简单配置几行代码,就能告别漫长的等待,把更多的时间花在编写代码上。

以下是一个简单的表格,总结了Webpack 5持久化缓存的关键配置项:

配置项 类型 默认值 说明
cache.type string memory 缓存类型,可选值为memoryfilesystem。建议使用filesystem
cache.cacheDirectory string .webpack 缓存目录,用于存储缓存文件。
cache.buildDependencies.config string[] [] 当这些文件发生变化时,缓存失效。通常包含webpack.config.js
cache.managedPaths string[] [] 告诉 Webpack 哪些路径下的文件是由包管理器管理的。Webpack 会更智能地处理这些文件,提高缓存的命中率。
cache.store string pack 定义缓存存储的方式。默认是pack,也可以设置为’idle’。设置为idle时,缓存会在构建完成一段时间后才写入磁盘,可以提高构建速度,但可能会导致缓存丢失。通常情况下,使用默认值即可。

最后的叮嘱:持续学习,拥抱变化

Webpack是一个不断发展的工具,新的特性和优化层出不穷。希望大家能够持续学习,不断探索Webpack的更多可能性,让我们的前端开发更加高效和愉快!

好了,今天的讲座就到这里,感谢大家的聆听!希望大家都能用上Webpack 5的持久化缓存,告别构建等待的烦恼!大家晚安!有什么问题可以在评论区留言,我会尽力解答。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注