缓存是常用的性能优化手段之一,其本质是空间换时间。(缓存属于延后优化策略,当然也可以提前优化,比如预加载)
在webpack4时代需要借助loader和plugin来实现本地缓存(就是将构建产物暂存在本地,如果没有更新则复用构建结果)。在v5时代,webpack已经内置了缓存相关的配置。
其基本逻辑是:在首次构建完毕后将 Module、Chunk、ModuleGraph 三类对象的状态序列化并记录到缓存文件中;在下次构建开始时,尝试读入并恢复这些对象的状态,从而跳过执行 Loader 链、解析 AST、解析依赖等耗时操作,从而提升编译性能。

v5的cache配置

webpack5开启本地缓存的配置方式非常简单:

  1. module.exports = {
  2. //...
  3. cache: {
  4. type: 'filesystem'
  5. },
  6. //...
  7. };

就上面这三行代码,就能开启本地化缓存了。
当然,webpack还提供了其他配置:

  • cache.type:缓存类型,支持 ‘memory’ | ‘filesystem’,需要设置为 filesystem 才能开启持久缓存;
  • cache.cacheDirectory:缓存文件路径,默认为 node_modules/.cache/webpack ,最终的缓存目标是 cache.cacheDirectory + cache.name 的混合;
  • cache.maxAge:失效时间,默认值为 5184000000
  • cache.buildDependencies:额外的依赖文件,当这些文件内容发生变化时,缓存会完全失效而执行完整的编译构建,通常可设置为各种配置文件;
  • cache.profile:是否输出缓存处理过程的详细日志,默认为 false

当然还有很多配置项,可参考:

v4时代的缓存

在webpack4时代,本地持久化缓存的能力还没有集成进webpack,所以想要使用缓存可以通过:
hard-source-webpack-plugincache-loader,以及loader自带的缓存能力,比如babel-loader;

hard-source-webpack-plugin

hard-source-webpack-plugin 实现的缓存效果和webpack5自带的效果差不多,缓存的比较全面(不仅仅缓存了 Loader 运行结果,还保存了 Webpack 构建过程中许多中间数据,包括:模块、模块关系、模块 Resolve 结果、Chunks、Assets 等)。

  1. yarn add -D hard-source-webpack-plugin
  1. const HardSourceWebpackPlugin = require("hard-source-webpack-plugin");
  2. module.exports = {
  3. // ...
  4. plugins: [
  5. new HardSourceWebpackPlugin(),
  6. ],
  7. };

cache-loader

cache-loader 也很常用,但只缓存了 Loader 执行结果,整体效果不如 Webpack5 内置的缓存功能。

  1. module.exports = {
  2. // ...
  3. module: {
  4. rules: [{
  5. test: /\.js$/,
  6. use: ['cache-loader', 'babel-loader', 'eslint-loader']
  7. }]
  8. },
  9. // ...
  10. };

cache-loader 还提供了一系列控制缓存逻辑的配置属性,特别是 read/write 可以用于改变缓存数据的持久化逻辑,借助这两个属性我们甚至能够实现多台机器间的缓存共享。

  1. const redis = require("redis");
  2. const client = redis.createClient();
  3. // 读数据
  4. async function read(key, callback) {
  5. // ...
  6. const result = await client.get(key);
  7. const data = JSON.parse(result);
  8. callback(null, data);
  9. }
  10. // 写数据
  11. async function write(key, data, callback) {
  12. // ...
  13. await client.set(key, JSON.stringify(data));
  14. callback();
  15. }
  16. module.exports = {
  17. // ...
  18. module: {
  19. rules: [
  20. {
  21. test: /\.js$/,
  22. use: [
  23. {
  24. loader: "cache-loader",
  25. // 传入 read、write 函数
  26. options: { read, write },
  27. },
  28. "babel-loader",
  29. ],
  30. },
  31. ],
  32. },
  33. };

webpack组件自带的缓存功能

一些webpack的插件或者loader也提供的有缓存功能,常用的有:

  • babel-loader: 设置 cacheDirectory = true 即可开启缓存功能,默认情况下,缓存内容会被保存到 node_modules/.cache/babel-loader 目录,你也可以通过 cacheDirectory = ‘dir’ 属性设置缓存路径

    1. module.exports = {
    2. // ...
    3. module: {
    4. rules: [{
    5. test: /\.m?js$/,
    6. loader: 'babel-loader',
    7. options: {
    8. cacheDirectory: true,
    9. },
    10. }]
    11. },
    12. // ...
    13. };
  • ESLint:eslint-loader/eslint-webpack-plugin,设置 cache = true

    1. module.exports = {
    2. plugins: [
    3. new ESLintPlugin({ cache: true }),
    4. ],
    5. };
  • Stylelint:stylelint-webpack-plugin设置 cache = true

    1. module.exports = {
    2. plugins: [
    3. new StylelintPlugin({ files: '**/*.css', cache: true }),
    4. ],
    5. };