CC 4.0 协议声明

本节内容派生于以下链接指向的内容 ,并遵守 CC BY 4.0 许可证的规定。

以下内容如果没有特殊声明,可以认为都是基于原内容的修改和删减后的结果。

Experiments

该选项允许用户开启和尝试一些实验性的功能。

  • 类型: object
TIP

在 minor release 中,Rspack 可能对这些实验性特性的 public API 做一些调整,并在更新日志中对这些变动进行详细的说明。因此,如果你使用了实验性特性,请留意 minor 版本的更新日志。

experiments.asyncWebAssembly

  • 类型: boolean
  • 默认值: false

支持基于新规范的 WebAssembly,这使 WebAssembly 模块成为异步模块。

rspack.config.js
module.exports = {
  experiments: {
    asyncWebAssembly: true,
  },
};

当设置 experiments.futureDefaultstrue 时,默认启用此功能。

experiments.outputModule

  • 类型: boolean
  • 默认值: false

开启之后,将尽可能输出符合 ECMAScript 语法的代码。例如,使用 import() 加载 chunk,使用 ESM exports 等等。

module.exports = {
  experiments: {
    outputModule: true,
  },
};

experiments.css

  • 类型: boolean
  • 默认值: false

启用原生 CSS 支持和 CSS 相关的 parser 和 generator options:

基本示例:

rspack.config.js
module.exports = {
  experiments: {
    css: true,
  },
};

experiments.futureDefaults

  • 类型: boolean
  • 默认值: false

使用下一个主版本 Rspack 的默认值,并在任何有问题的地方显示警告。

rspack.config.js
module.exports = {
  experiments: {
    futureDefaults: true,
  },
};

experiments.topLevelAwait

  • 类型: boolean
  • 默认值: true

开启打包 Top-level await 的支持,Top-level await 仅能在 ModuleTypejavascript/esm 的模块中使用。

默认开启,可通过该配置关闭:

rspack.config.js
module.exports = {
  experiments: {
    topLevelAwait: false,
  },
};

experiments.lazyCompilation

  • 类型: boolean | LazyCompilationOptions
  • 默认值: false
type LazyCompilationOptions =
  | boolean
  | {
      backend?: {
        /**
         * 自定义客户端脚本路径。
         */
        client?: string;
        /**
         * 指定从服务器监听的端口或选项。
         */
        listen?: number | ListenOptions | ((server: Server) => void);
        /**
         * 指定客户端使用的协议。
         */
        protocol?: 'http' | 'https';
        /**
         * 指定如何创建处理 EventSource 请求的服务器。
         */
        server?:
          | ServerOptionsImport<typeof IncomingMessage>
          | ServerOptionsHttps<typeof IncomingMessage, typeof ServerResponse>
          | (() => Server);
      };
      /**
       * 为 entries 启用 lazy compilation
       */
      entries?: boolean;
      /**
       * 为 dynamic imports 启用 lazy compilation
       */
      imports?: boolean;
      /**
       * 指定哪些导入的模块应该被延迟编译
       */
      test?: RegExp | ((m: Module) => boolean);
    };

开启懒编译,这对提高多入口应用(MPA)或大型单页面应用(SPA)的 dev 启动性能会非常有帮助。例如你有二十个入口,只有访问到的入口才会进行构建,或者如果项目中存在非常多的 import(),每一个 import() 所指向的模块都只有在被真正访问到时,才进行构建。

如果设置为 true,则默认会对入口模块以及 import() 指向的模块进行懒编译。你可以通过配置对象形式,来决定是否只对入口或只对 import() 生效。entries 决定是否对入口生效,import() 决定是否对 import() 生效。

rspack.config.js
const isDev = process.env.NODE_ENV === 'development';

module.exports = {
  experiments: {
    // 仅在 dev 模式下开启
    lazyCompilation: isDev,
  },
};

除此以外你还可以配置 test 来更细粒度控制对哪些模块进行懒编译。test 可以是一个正则表达式,只对该正则匹配到的模块进行懒编译,test 也可以是一个函数,函数的输入是 Module 类型,返回 boolean 类型,表示是否命中懒编译逻辑。

NOTE

当前 lazy compilation 是对齐 webpack 实现的,并且仍处于实验性阶段。在部分场景下,lazy compilation 可能无法按照预期工作,或是性能提升不明显。

lazyCompilation.backend.listen

  • 类型: number | ListenOptions
type ListenOptions = {
  port?: number | undefined;
  host?: string | undefined;
  backlog?: number | undefined;
  path?: string | undefined;
  exclusive?: boolean | undefined;
  readableAll?: boolean | undefined;
  writableAll?: boolean | undefined;
  /**
   * @default false
   */
  ipv6Only?: boolean | undefined;
};

排除 HMR client

如果你未使用 Rspack 的 dev server,而是使用自己的 server 作为开发服务器,一般会在 entry 配置中加入另外的 client 代码来开启 HMR 等能力,那么最好通过配置 test 来将该 client 模块从懒编译模块中排除出去。

如果不排除掉,并且开启 entry 的懒编译,该 client 在第一次访问页面时不会被编译,因此需要一次额外的刷新才能让其真正生效。

const { rspack } = require('@rspack/core');

const options = {
  experiments: {
    lazyCompilation: {
      test(module) {
        const isMyClient = module.nameForCondition().endsWith('dev-client.js');
        // 让 dev-client.js 不被懒编译
        return !isMyClient;
      },
    },
  },
};
const compiler = rspack(options);

new compiler.webpack.EntryPlugin(compiler.context, 'dev-client.js', {
  // name: undefined 代表这是全局 entry,会插入到每一个 entry 前
  name: undefined,
}).apply(compiler);

experiments.layers

  • 类型: boolean
  • 默认值: false

控制是否启用 layer 功能,layer 可以为模块图中以一个模块作为起点的子图中的所有模块添加标识符前缀,用来与其他不同 layer 的模块进行区分,比如:

index.js 模块的 layer 为默认的 null,其 identifier./index.js,我们为其添加 layer = 'client',其 identifier 会变成 (client)/./index.js,这时这两个不同 layer 的 index.js 会被区分为不同的模块,因为其唯一标识 identifier 不一样,最终产物中也会存在这两个模块的产物。

模块默认的 layer 为 null,模块默认会继承其父模块的 layer,你可以通过 entryOptions.layer 为一个入口模块添加 layer,也可以通过 module.rule[].layer 为匹配到的模块添加 layer,同时可以通过 module.rule[].issuerLayer 根据父模块的 layer 进行匹配。

rspack.config.js
module.exports = {
  experiments: {
    layers: true,
  },
};

experiments.incremental

type Incremental = {
  make?: boolean;
  inferAsyncModules?: boolean;
  providedExports?: boolean;
  dependenciesDiagnostics?: boolean;
  sideEffects?: boolean;
  buildChunkGraph?: boolean;
  moduleIds?: boolean;
  chunkIds?: boolean;
  modulesHashes?: boolean;
  modulesCodegen?: boolean;
  modulesRuntimeRequirements?: boolean;
  chunksRuntimeRequirements?: boolean;
  chunksHashes?: boolean;
  chunksRender?: boolean;
  emitAssets?: boolean;
};

是否增量地进行重构建,加快重构建或 HMR 的速度,建议仅在开发时启用:

const isDev = process.env.NODE_ENV;
module.exports = {
  mode: isDev ? 'development' : 'production',
  experiments: {
    incremental: isDev,
  },
};

true 表示对全部阶段启用增量,false 表示对全部阶段关闭增量,也可以仅对指定的部分阶段开启增量:

module.exports = {
  experiments: {
    // 对全部阶段启用增量
    incremental: true,
    // 对全部阶段关闭增量
    incremental: false,
    // 仅对指定的部分阶段开启增量
    incremental: {
      make: true,
      emitAssets: true,
    },
  },
};

目前 Rspack 默认开启 makeemitAssets 阶段的增量,这也是之前 Rspack v1.0 的默认行为。随着该特性的进一步稳定,我们会默认开启更多阶段的增量,直到完全启用。

TIP

该特性属于实验性特性,可前往 rspack#8106 查看其相关进度,也可在此 issue 中反馈 bugs 以及任何与之相关的反馈信息。

experiments.parallelCodeSplitting

  • 类型: boolean
  • 默认值: false

开启后会启用新的多线程 code splitting 算法,如果你的项目中包含较多的动态引用,开启后可以显著降低 code splitting 阶段耗时,在未来 Rspack 会默认开启这个配置项。

rspack.config.js
module.exports = {
  experiments: {
    parallelCodeSplitting: true,
  },
};

experiments.rspackFuture

  • 类型: object
  • 默认值: 参考下方各项配置

用于控制是否开启 Rspack 未来的默认行为,详情请参考这里

rspackFuture.bundlerInfo

  • 类型:
    type BundlerInfo = {
      version?: string,
      bundler?: string,
      force?: ('version' | 'uniqueId')[]boolean;
    };

用于在生成产物中注入当前使用的 Rspack 信息。其中:

  • version:用于指定 Rspack 版本,默认读取 @rspack/core/package.json 中的 version 字段。
  • bundler:用于指定打包工具名称,默认为 rspack
  • force:是否强制注入 Rspack 信息,会以运行时模块的形式加入到产物中,默认为 true 即强制注入,可通过数组选择强制注入的项目。

关闭默认注入

可通过将 force 设定为 false 来关闭默认注入,此时仅在检测到代码中使用了 __rspack_version____rspack_unique_id__ 时才会注入:

rspack.config.js
module.exports = {
  experiments: {
    rspackFuture: {
      bundlerInfo: { force: false },
    },
  },
};

experiments.cache

  • 类型: ExperimentCacheOptions

  • 默认值: production 模式 为 false, development 模式 为 true

type ExperimentCacheOptions =
  | boolean
  | {
      type: 'memory';
    }
  | {
      type: 'persistent';
      buildDependencies?: string[];
      version?: string;
      snapshot?: {
        immutablePaths?: Array<string | RegExp>;
        unmanagedPaths?: Array<string | RegExp>;
        managedPaths?: Array<string | RegExp>;
      };
      storage?: {
        type: 'filesystem';
        directory?: string;
      };
    };

控制实验性的缓存行为,此配置依赖全局开启缓存,需配置 config.cachetrue 才有效。

Note

production 模式下 config.cache 默认值为 false,这会导致此配置项失效,建议直接配置 config.cachetrue

禁用缓存

可以配置 experiment.cachefalse 来禁用缓存,这与配置 config.cachefalse 没有差别。

rspack.config.js
module.exports = {
  cache: true,
  experiments: {
    cache: false,
  },
};

内存缓存

可以配置 experiment.cachetrue 或者 { "type": "memory" } 来启动内存缓存。

rspack.config.js
module.exports = {
  cache: true,
  experiments: {
    cache: true,
  },
};

持久化缓存

可以配置 experiment.cache{ "type": "persistent" } 来启用持久化缓存。

rspack.config.js
module.exports = {
  cache: true,
  experiments: {
    cache: {
      type: 'persistent',
    },
  },
};

cache.buildDependencies

  • 类型: string[]

  • 默认值: []

cache.buildDependencies 是一个包含构建依赖的文件数组,Rspack 将使用其中每个文件的哈希值来使持久化缓存无效。

TIP

推荐添加 __filename 到 buildDependencies 中

rspack.config.js
module.exports = {
  cache: true,
  experiments: {
    cache: {
      type: 'persistent',
      buildDependencies: [__filename, path.join(__dirname, './tsconfig.json')],
    },
  },
};

cache.version

  • 类型: string

  • 默认值: ""

缓存数据的版本,不同版本缓存相互隔离。

持久化缓存失效

除了 buildDependenciesversion 配置会影响持久化缓存失效,Rspack 还会在以下字段变化时使持久化缓存失效。

cache.snapshot

配置快照策略,Snapshot 用于在热启动时判断哪些文件在停机时被修改。支持以下配置:

snapshot.immutablePaths
  • 类型: (RegExp | string)[]

  • 默认值: []

不可变文件的路径数组,这些文件的变动在热启动时会被忽略。

snapshot.managedPaths
  • 类型: (RegExp | string)[]

  • 默认值: [/\/node_modules\//]

由包管理器管理的路径数组,热启动时会通过 package.json 中的版本来判断是否修改。

snapshot.unmanagedPaths
  • 类型: (RegExp | string)[]

  • 默认值: []

指定 snapshot.managedPaths 中不受包管理器管理的路径数组。

cache.storage

  • 类型: { type: 'filesystem', directory: string }

  • 默认值: { type: 'filesystem', directory: 'node_modules/.cache/rspack' }

配置缓存存储,目前仅支持文件系统存储,可以通过 directory 设置缓存路径,默认为 node_modules/.cache/rspack

rspack.config.js
module.exports = {
  cache: true,
  experiments: {
    cache: {
      type: 'persistent',
      storage: {
        type: 'filesystem',
        directory: 'node_modules/.cache/rspack',
      },
    },
  },
};
TIP

Rspack 会在 storage.directory 目录下基于 config.nameconfig.modebuildDependencies中的文件内容 和 version 生成缓存文件夹。

Rspack 会在启动时自动清理掉过长时间(7 天)没有访问的缓存文件夹。

从 webpack config 迁移

Rspack cache 配置与 webpack cache 配置的用法存在差异, 你可以参考以下步骤对 webpack cache 配置进行迁移。

  1. 根据 webpack 缓存类型,设置 Rspack 缓存类型,持久化缓存继续后续步骤,其他类型缓存到这一步即可。
rspack.config.js
module.exports = {
- cache: {
-   type: 'filesystem',
- },
+ cache: true,
+ experiments: {
+   cache: {
+     type: 'persistent',
+   },
+ },
};
  1. 迁移 cache.buildDependencies
rspack.config.js
module.exports = {
- cache: {
-   buildDependencies: {
-     config: [__filename, path.join(__dirname, "package.json")],
-     ts: [path.join(__dirname, "tsconfig.json")]
-   }
- },
  experiments: {
    cache: {
      type: "persistent",
+     buildDependencies: [
+       __filename,
+       path.join(__dirname, "package.json"),
+       path.join(__dirname, "tsconfig.json")
+     ]
    },
  },
};
  1. 迁移 cache.version & cache.name
rspack.config.js
module.exports = {
- cache: {
-   name: `${config.name}-${config.mode}-${otherFlags}`,
-   version: appVersion
- },
  experiments: {
    cache: {
      type: "persistent",
+     version: `${config.name}-${config.mode}-${otherFlags}-${appVersion}`
    },
  },
};
  1. 迁移 snapshot
rspack.config.js
module.exports = {
- snapshot: {
-   immutablePaths: [path.join(__dirname, "constant")],
-   managedPaths: [path.join(__dirname, "node_modules")],
-   unmanagedPaths: []
- },
  experiments: {
    cache: {
      type: "persistent",
+     snapshot: {
+       immutablePaths: [path.join(__dirname, "constant")],
+       managedPaths: [path.join(__dirname, "node_modules")],
+       unmanagedPaths: []
+     }
    },
  },
};
  1. 迁移 cache.cacheDirectory
rspack.config.js
module.exports = {
- cache: {
-   cacheDirectory: path.join(__dirname, "node_modules/.cache/test")
- },
  experiments: {
    cache: {
      type: "persistent",
+     storage: {
+       type: "filesystem",
+       directory: path.join(__dirname, "node_modules/.cache/test")
+     }
    },
  },
};

示例代码:

function transform(webpackConfig, rspackConfig) {
  rspackConfig.experiments = rspackConfig.experiments || {};
  if (webpackConfig.cache === undefined) {
    webpackConfig.cache = webpackConfig.mode === 'development';
  }
  // 1. 如果使用禁用缓存,则直接配置 `experiments.cache` 为 `false`
  if (webpackConfig.cache === false) {
    rspackConfig.experiments.cache = false;
    return;
  }
  // 2. 如果使用内存缓存,则直接配置 `experiments.cache` 为 `true`
  if (webpackConfig.cache === true || webpackConfig.cache.type === 'memory') {
    rspackConfig.experiments.cache = true;
    return;
  }
  // 3. 持久化缓存 配置 `experiments.cache` 为 `{ type: "persistent" }`
  rspackConfig.experiments.cache = { type: 'persistent' };
  // 4. 从 webpack 配置中构建 `experiments.cache` 其他配置
  rspackConfig.experiments.cache.buildDependencies = Object.values(
    webpackConfig.cache.buildDependencies || {},
  ).flat();
  rspackConfig.experiments.cache.version = [
    webpackConfig.cache.name,
    webpackConfig.cache.version,
  ].join();
  rspackConfig.experiments.cache.snapshot = {
    immutablePaths: webpackConfig.snapshot?.immutablePaths,
    managedPaths: webpackConfig.snapshot?.managedPaths,
    unmanagedPaths: webpackConfig.snapshot?.unmanagedPaths,
  };
  rspackConfig.experiments.cache.storage = {
    type: 'filesystem',
    directory: webpackConfig.cache?.cacheDirectory,
  };
}