底层插件
这些插件是 Rspack 对外暴露的底层构件,主要用于实现目标预设、运行时模板、子编译器和上层插件。
使用建议
常规应用构建应优先使用对应的上层配置。直接使用这些插件主要适用于自定义编译器、子编译器和高级集成。
底层插件分为以下类别:
environment
影响编译器环境和运行目标的插件。
ElectronTargetPlugin
new rspack.electron.ElectronTargetPlugin(context);
ElectronTargetPlugin 会将 Electron 内置模块保留为外部依赖,使其在运行时由 Electron 加载。传入 'main'、'preload' 或 'renderer',可以额外外置对应进程中可用的模块。
externalsPresets.electron、externalsPresets.electronMain、externalsPresets.electronRenderer 和 externalsPresets.electronPreload 配置会在内部应用该插件。
对于常规 Electron 应用,推荐使用对应的 target:
rspack.config.mjs
export default {
target: 'electron-main',
entry: './src/main.js',
};
配置子编译器时,可以直接将插件应用到该编译器:
new compiler.rspack.electron.ElectronTargetPlugin('main').apply(childCompiler);
NodeEnvironmentPlugin
new rspack.node.NodeEnvironmentPlugin(options);
NodeEnvironmentPlugin 会为编译器安装 infrastructure logger、带缓存的 Node.js 输入文件系统、作为输出文件系统的 Node.js fs 模块以及 watch 文件系统。rspack() API 会自动将它应用到根编译器。
当自定义编译器需要独立的 Node.js 文件系统环境时,可以传入该编译器标准化后的 infrastructure logging 选项并直接应用插件:
new compiler.rspack.node.NodeEnvironmentPlugin({
infrastructureLogging: childCompiler.options.infrastructureLogging,
}).apply(childCompiler);
该插件只配置编译器 I/O 和日志,不会设置 JavaScript 运行目标。需要将 Node.js 内置模块保留为外部依赖时,应使用 NodeTargetPlugin。
NodeTargetPlugin
new rspack.node.NodeTargetPlugin();
NodeTargetPlugin 会将 Node.js 内置模块和使用 node: scheme 的请求保留为外部依赖,使其由 Node.js 运行时加载,而不是被 Rspack 打进 bundle。externalsPresets.node 配置会在内部应用该插件。
对于常规 Node.js 应用,推荐使用 node target:
rspack.config.mjs
export default {
target: 'node',
entry: './src/index.js',
};
配置子编译器时,可以直接将插件应用到该编译器:
new compiler.rspack.node.NodeTargetPlugin().apply(childCompiler);
entry
向 compilation 添加入口 chunk 的插件。
DynamicEntryPlugin
new rspack.DynamicEntryPlugin(context, entry);
DynamicEntryPlugin 会在每次触发 make 事件时调用入口函数,并将函数返回的入口添加到 compilation 中,因此入口列表可以在 watch 重新构建之间发生变化。
直接调用该 API 时需要传入标准化后的入口描述,因此每个 import 的值都是数组:
rspack.config.mjs
import { rspack } from '@rspack/core';
const context = process.cwd();
export default {
context,
entry: {},
plugins: [
new rspack.DynamicEntryPlugin(context, async () => ({
main: {
import: ['./src/index.js'],
},
})),
],
};
常规构建应优先使用 entry 函数,Rspack 会自动将它标准化并传给该插件。
EntryOptionPlugin
new rspack.EntryOptionPlugin();
EntryOptionPlugin 用于处理 compiler 的 entryOption hook。对于静态入口,它会为每个入口请求应用 EntryPlugin;对于函数入口,则会应用 DynamicEntryPlugin。Rspack 会自动将它应用到根编译器。
为子编译器添加标准化后的入口时,可以使用静态的 applyEntryOption 方法:
const childOptions = compiler.rspack.config.getNormalizedRspackOptions({
entry: {
child: './src/child.js',
},
});
compiler.rspack.EntryOptionPlugin.applyEntryOption(
childCompiler,
compiler.context,
childOptions.entry,
);
output
影响模块、chunk 和运行时加载代码生成的插件。
EnableChunkLoadingPlugin
new rspack.javascript.EnableChunkLoadingPlugin(type);
EnableChunkLoadingPlugin 会启用指定 chunk loading 类型所需的运行时模块。Rspack 通常会根据 output.enabledChunkLoadingTypes 收集到的类型应用该插件。
支持的内置类型包括 'jsonp'、'import-scripts'、'require'、'async-node' 和 'import'。
当动态入口选择了 Rspack 在配置标准化阶段无法发现的类型时,可以直接应用该插件:
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
entry: () => ({
main: {
import: './src/index.js',
chunkLoading: 'jsonp',
},
}),
output: {
chunkLoading: false,
},
plugins: [new rspack.javascript.EnableChunkLoadingPlugin('jsonp')],
};
自定义 chunk loading 实现可以在安装相应运行时钩子后调用 EnableChunkLoadingPlugin.setEnabled(compiler, type)。该方法只注册类型,并不会实现 chunk loading。
EnableLibraryPlugin
new rspack.library.EnableLibraryPlugin(type);
EnableLibraryPlugin 会向编译器注册一种 library 输出类型。Rspack 通常会根据 output.enabledLibraryTypes 收集到的类型应用该插件。
下面的动态入口选择 'var' library 类型。由于 Rspack 无法在配置标准化阶段检查函数入口,因此需要显式启用该类型:
src/index.js
export const add = (a, b) => a + b;
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
entry: () => ({
main: {
import: './src/index.js',
library: {
name: 'MathLibrary',
type: 'var',
},
},
}),
plugins: [new rspack.library.EnableLibraryPlugin('var')],
};
常规 library 构建应优先使用 output.library,Rspack 会自动启用其中的 library 类型。
EnableWasmLoadingPlugin
new rspack.wasm.EnableWasmLoadingPlugin(type);
EnableWasmLoadingPlugin 会启用指定 WebAssembly 加载类型所需的运行时模块。Rspack 通常会根据 output.enabledWasmLoadingTypes 收集到的类型应用该插件。
支持的类型包括 'fetch'、'async-node' 和 'universal'。
下面的示例将 output.wasmLoading 设为 false 以关闭自动配置,然后直接应用 EnableWasmLoadingPlugin 安装 'fetch' 加载运行时:
src/index.js
import { add } from './add.wasm';
console.log(add(1, 2));
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
target: 'web',
entry: './src/index.js',
experiments: {
asyncWebAssembly: true,
},
output: {
wasmLoading: false,
},
plugins: [new rspack.wasm.EnableWasmLoadingPlugin('fetch')],
};
常规构建应优先使用 output.wasmLoading,Rspack 会自动启用所选类型。
new rspack.EvalDevToolModulePlugin(options);
EvalDevToolModulePlugin 会使用 eval 包裹每个非 external JavaScript 模块并添加 sourceURL,使浏览器开发者工具可以显示原始模块名称。设置 devtool: 'eval' 时,Rspack 会自动应用该插件。
下面的配置直接应用该插件,并使用 dashboard 作为 source URL 的 namespace:
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
mode: 'development',
devtool: false,
plugins: [
new rspack.EvalDevToolModulePlugin({
namespace: 'dashboard',
}),
],
};
可以通过 moduleFilenameTemplate 和 sourceUrlComment 选项自定义生成的模块 URL 和注释格式。
FetchCompileAsyncWasmPlugin
new rspack.web.FetchCompileAsyncWasmPlugin();
FetchCompileAsyncWasmPlugin 会添加在浏览器中获取并编译异步 WebAssembly 模块的运行时代码。EnableWasmLoadingPlugin('fetch') 会在内部应用这个实现。
下面的示例关闭 WebAssembly loading 的自动配置,并直接安装 fetch 实现:
src/index.js
import { add } from './add.wasm';
console.log(add(1, 2));
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
target: 'web',
entry: './src/index.js',
experiments: {
asyncWebAssembly: true,
},
output: {
wasmLoading: false,
},
plugins: [new rspack.web.FetchCompileAsyncWasmPlugin()],
};
常规 web 构建应优先使用 output.wasmLoading: 'fetch',Rspack 会自动启用相同的运行时实现。
JsonpTemplatePlugin
new rspack.web.JsonpTemplatePlugin();
JsonpTemplatePlugin 用于配置子编译器的浏览器产物。它会将 output.chunkLoading 设置为 'jsonp',应用 'array-push' chunk format,并启用 JSONP chunk loading 所需的运行时代码。
下面的浏览器入口会生成一个异步 chunk:
src/browser-child.js
document.querySelector('button').addEventListener('click', async () => {
const { message } = await import('./message.js');
console.log(message);
});
src/message.js
export const message = 'Hello from the child compiler';
下面的配置会创建一个子编译器,并直接应用 JsonpTemplatePlugin:
rspack.config.mjs
export default {
target: 'web',
entry: {},
plugins: [
(compiler) => {
compiler.hooks.make.tapAsync(
'BrowserChildCompiler',
(compilation, callback) => {
const childCompiler = compilation.createChildCompiler(
'browser-child',
{
filename: 'browser-child.js',
chunkFilename: '[name].browser-child.js',
},
[
new compiler.rspack.web.JsonpTemplatePlugin(),
new compiler.rspack.EntryPlugin(
compiler.context,
'./src/browser-child.js',
{ name: 'browser-child' },
),
],
);
childCompiler.runAsChild((error) => callback(error));
},
);
},
],
};
JsonpTemplatePlugin 会让子编译器生成 array-push chunk,并在需要加载异步 chunk 时向页面添加 script。
对于常规 web 构建,推荐使用 target: 'web'。Rspack 会通过该 target 的默认配置选择 'array-push' chunk format 和 'jsonp' chunk loading。设置 output.chunkLoading: 'jsonp' 只会选择加载实现,并不会应用 JsonpTemplatePlugin 或选择 chunk format。
NodeTemplatePlugin
new rspack.node.NodeTemplatePlugin(options);
NodeTemplatePlugin 用于配置子编译器的 Node.js 产物。它会应用 'commonjs' chunk format,默认将 output.chunkLoading 设置为 'require',并启用所需的 chunk loading 运行时代码。
asyncChunkLoading
当 asyncChunkLoading 为 true 时,该插件会使用 'async-node' chunk loading,而不是 'require'。
下面的 Node.js 入口会生成一个异步 chunk:
src/node-child.js
async function main() {
const { run } = await import('./task.js');
run();
}
main();
src/task.js
export function run() {
console.log('Task completed');
}
下面的配置会创建一个子编译器,并直接应用 NodeTemplatePlugin:
rspack.config.mjs
export default {
target: 'node',
entry: {},
plugins: [
(compiler) => {
compiler.hooks.make.tapAsync(
'NodeChildCompiler',
(compilation, callback) => {
const childCompiler = compilation.createChildCompiler(
'node-child',
{
filename: 'node-child.js',
chunkFilename: '[name].node-child.js',
},
[
new compiler.rspack.node.NodeTemplatePlugin(),
new compiler.rspack.EntryPlugin(
compiler.context,
'./src/node-child.js',
{ name: 'node-child' },
),
],
);
childCompiler.runAsChild((error) => callback(error));
},
);
},
],
};
NodeTemplatePlugin 会让子编译器生成 CommonJS chunk,并通过 require 加载其中的异步 chunk。
对于常规 Node.js 构建,推荐使用 target: 'node'。Rspack 会通过该 target 的默认配置选择 'commonjs' chunk format 和 'require' chunk loading。设置 output.chunkLoading: 'require' 只会选择加载实现,并不会应用 NodeTemplatePlugin 或选择 chunk format。
WebWorkerTemplatePlugin
new rspack.webworker.WebWorkerTemplatePlugin();
WebWorkerTemplatePlugin 用于配置子编译器的 Web Worker 产物。它会将 output.chunkLoading 设置为 'import-scripts',应用 'array-push' chunk format,并启用基于 importScripts 的 chunk loading 运行时代码。
下面的 Worker 入口会生成一个异步 chunk:
src/worker-child.js
self.onmessage = async ({ data }) => {
const { double } = await import('./math.js');
self.postMessage(double(data));
};
src/math.js
export const double = (value) => value * 2;
下面的配置会创建一个子编译器,并直接应用 WebWorkerTemplatePlugin:
rspack.config.mjs
export default {
target: 'webworker',
entry: {},
plugins: [
(compiler) => {
compiler.hooks.make.tapAsync(
'WorkerChildCompiler',
(compilation, callback) => {
const childCompiler = compilation.createChildCompiler(
'worker-child',
{
filename: 'worker-child.js',
chunkFilename: '[name].worker-child.js',
},
[
new compiler.rspack.webworker.WebWorkerTemplatePlugin(),
new compiler.rspack.EntryPlugin(
compiler.context,
'./src/worker-child.js',
{ name: 'worker-child' },
),
],
);
childCompiler.runAsChild((error) => callback(error));
},
);
},
],
};
WebWorkerTemplatePlugin 会让子编译器生成 array-push chunk,并通过 importScripts 加载其中的异步 chunk。
对于常规 Web Worker 构建,推荐使用 target: 'webworker'。Rspack 会通过该 target 的默认配置选择 'array-push' chunk format 和 'import-scripts' chunk loading。设置 output.chunkLoading: 'import-scripts' 只会选择加载实现,并不会应用 WebWorkerTemplatePlugin 或选择 chunk format。
loader
用于自定义 loader 执行上下文的插件。
LoaderOptionsPlugin
new rspack.LoaderOptionsPlugin(options);
LoaderOptionsPlugin 会将自定义选项字段复制到匹配 test、include 和 exclude 的资源所对应的 loader context 上。匹配字段本身只用于过滤,不会被复制。
下面的 loader 会从 context 中读取自定义的 message 属性:
loaders/message-loader.cjs
module.exports = function () {
return `export default ${JSON.stringify(this.message)};`;
};
插件只在处理 .message 文件时提供该属性:
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
entry: './src/welcome.message',
module: {
rules: [
{
test: /\.message$/,
use: './loaders/message-loader.cjs',
},
],
},
plugins: [
new rspack.LoaderOptionsPlugin({
test: /\.message$/,
message: 'Hello from the loader',
}),
],
};
该插件主要用于兼容从 this 读取自定义属性的 loader。新编写的 loader 通常应通过自身的 loader options 接收参数。
LoaderTargetPlugin
new rspack.LoaderTargetPlugin(target);
LoaderTargetPlugin 会将 target 赋值给每个 loader context 的 this.target。当自定义编译器需要让 loader 读取到与编译器配置不同的 target 时,可以使用该插件。
下面的 loader 会将输入替换为它读取到的 target:
loaders/target-loader.cjs
module.exports = function () {
return `console.log(${JSON.stringify(this.target)});`;
};
虽然构建的 target 是 web,下面的插件会让 loader 读取到 'node':
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
target: 'web',
entry: './src/index.js',
module: {
rules: [
{
test: /index\.js$/,
use: './loaders/target-loader.cjs',
},
],
},
plugins: [new rspack.LoaderTargetPlugin('node')],
};
常规构建应优先使用顶层的 target 配置。
module federation
这些插件实现了 Module Federation 的 exposes、remotes 和 shared 能力。常规应用构建应优先使用 ModuleFederationPlugin,由它统一配置这些底层插件。
ContainerPlugin
new rspack.container.ContainerPlugin(options);
ContainerPlugin 会创建一个 container 入口,通过 Module Federation 的 get 和 init 接口暴露本地模块。它是 exposes 配置的底层实现。
下面的配置会生成 remoteEntry.js,并将 src/Button.js 暴露为 ./Button:
rspack.config.mjs
import { container } from '@rspack/core';
export default {
entry: {},
plugins: [
new container.ContainerPlugin({
name: 'catalog',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/Button.js',
},
}),
],
};
ContainerReferencePlugin
new rspack.container.ContainerReferencePlugin(options);
ContainerReferencePlugin 会将远程 container 注册为 external,并添加从远程加载模块所需的运行时代码。它是 remotes 配置的底层实现。
使用下面的配置后,import('catalog/Button') 这样的导入会从远程 container 加载 ./Button:
rspack.config.mjs
import { container } from '@rspack/core';
export default {
entry: './src/index.js',
plugins: [
new container.ContainerReferencePlugin({
remoteType: 'script',
remotes: {
catalog: 'catalog@http://localhost:3001/remoteEntry.js',
},
}),
],
};
ConsumeSharedPlugin
new rspack.sharing.ConsumeSharedPlugin(options);
ConsumeSharedPlugin 会从 share scope 中解析配置的模块请求。它可以检查版本与 singleton 要求,并在没有合适 provider 时使用本地模块作为 fallback。
下面的示例会从默认 share scope 中消费 singleton react,不检查版本,并在需要时回退到本地安装的 package:
rspack.config.mjs
import { sharing } from '@rspack/core';
export default {
entry: './src/index.js',
plugins: [
new sharing.ConsumeSharedPlugin({
consumes: {
react: {
import: 'react',
requiredVersion: false,
singleton: true,
},
},
}),
],
};
ProvideSharedPlugin
new rspack.sharing.ProvideSharedPlugin(options);
ProvideSharedPlugin 会将本地模块及其版本注册到 share scope 中,供其他构建消费。它是 shared 配置中 provider 部分的底层实现。
下面的简写形式会使用 react 作为 share key 提供本地安装的 react package,并从 package metadata 中推断版本:
rspack.config.mjs
import { sharing } from '@rspack/core';
export default {
plugins: [
new sharing.ProvideSharedPlugin({
provides: ['react'],
}),
],
};
SharePlugin
new rspack.sharing.SharePlugin(options);
SharePlugin 会根据同一份 shared 配置同时应用 ConsumeSharedPlugin 和 ProvideSharedPlugin。它等价于 ModuleFederationPlugin 中 shared 配置的底层实现。
下面的示例会将本地 react package 作为 fallback 提供,同时从默认 share scope 中消费 singleton 实例:
rspack.config.mjs
import { sharing } from '@rspack/core';
export default {
plugins: [
new sharing.SharePlugin({
enhanced: false,
shared: {
react: {
requiredVersion: false,
singleton: true,
},
},
}),
],
};
TreeShakingSharedPlugin
new rspack.sharing.TreeShakingSharedPlugin(options);
TreeShakingSharedPlugin 会为 Module Federation 共享依赖创建独立构建并优化导出。当至少一个 shared 依赖启用了 treeShaking 时,ModuleFederationPlugin 会自动应用该插件。
选项
mfConfig:用于配置共享依赖和产物的 ModuleFederationPluginOptions。
secondary:是否在独立构建中执行第二次 tree shaking,默认值为 false。
onBuildAssets:生成共享 fallback 产物后调用的回调函数。
直接应用该插件主要适用于部署平台执行二次构建的场景。它必须配合共享插件使用,以便 TreeShakingSharedPlugin 收集需要构建的共享模块:
src/index.js
import { add } from 'lodash-es';
console.log(add(1, 2));
rspack.config.mjs
import { sharing } from '@rspack/core';
const shared = {
'lodash-es': { treeShaking: { mode: 'server-calc' } },
};
export default {
entry: './src/index.js',
plugins: [
new sharing.SharePlugin({
enhanced: true,
shared,
}),
new sharing.TreeShakingSharedPlugin({
secondary: true,
mfConfig: {
name: 'app',
shared,
library: { type: 'var', name: 'App' },
},
}),
],
};
该插件只会为启用了 treeShaking 且保留本地实现的共享依赖创建独立构建。单独使用时,它不会生成 Module Federation stats 或 manifest 文件。当 ModuleFederationPlugin 在启用 manifest 生成的情况下在内部应用该插件时,生成的 fallback 产物信息会被写入这些文件。
experiments
RemoveDuplicateModulesPlugin
new rspack.experiments.RemoveDuplicateModulesPlugin();
RemoveDuplicateModulesPlugin 会查找同时出现在同一组多个 chunk 中的模块,并将它们移动到一个可复用或新创建的共享 chunk 中。Rspack 会在生成 modern-module library 产物时在内部使用该插件。
下面的两个入口都导入了同一个 src/shared.js 模块。关闭 splitChunks 后,将由 RemoveDuplicateModulesPlugin 提取这个重复模块:
rspack.config.mjs
import { rspack } from '@rspack/core';
export default {
entry: {
admin: './src/admin.js',
store: './src/store.js',
},
optimization: {
splitChunks: false,
},
plugins: [new rspack.experiments.RemoveDuplicateModulesPlugin()],
};
本页改编自 webpack 文档,遵循 CC BY 4.0,且已作修改。