Plugin Hooks
本章节介绍 Rsbuild 插件可用的 plugin hooks。
总览
Common Hooks
Dev Hooks
仅在执行 rsbuild dev
命令或 rsbuild.startDevServer()
方法时调用。
Build Hooks
仅在执行 rsbuild build
命令或 rsbuild.build()
方法时调用。
Preview Hooks
仅在执行 rsbuild preview
命令或 rsbuild.preview()
方法时调用。
Hooks 顺序
Dev Hooks
执行 rsbuild dev
命令或 rsbuild.startDevServer()
方法时,Rsbuild 会依次执行以下 hooks:
Build Hooks
执行 rsbuild build
命令或 rsbuild.build()
方法时,Rsbuild 会依次执行以下 hooks:
Preview Hooks
执行 rsbuild preview
命令或 rsbuild.preview()
方法时,Rsbuild 会依次执行以下 hooks:
回调函数顺序
默认行为
如果多个插件注册了相同的 hook,那么 hook 的回调函数会按照注册时的顺序执行。
在以下例子中,控制台会依次输出 '1'
和 '2'
:
const plugin1 = () => ({
setup: (api) => {
api.modifyRsbuildConfig(() => console.log('1'));
},
});
const plugin2 = () => ({
setup: (api) => {
api.modifyRsbuildConfig(() => console.log('2'));
},
});
rsbuild.addPlugins([plugin1, plugin2]);
order 字段
在注册 hook 时,可以通过 order
字段来声明 hook 的顺序。
type HookDescriptor<T extends (...args: any[]) => any> = {
handler: T;
order: 'pre' | 'post' | 'default';
};
在以下例子中,控制台会依次输出 '2'
和 '1'
,因为 plugin2 在调用 modifyRsbuildConfig 时设置了 order 为 pre
。
const plugin1 = () => ({
setup: (api) => {
api.modifyRsbuildConfig(() => console.log('1'));
},
});
const plugin2 = () => ({
setup: (api) => {
api.modifyRsbuildConfig({
handler: () => console.log('2'),
order: 'pre',
});
},
});
rsbuild.addPlugins([plugin1, plugin2]);
Common Hooks
modifyRsbuildConfig
修改传递给 Rsbuild 的配置项,你可以直接修改传入的 config 对象,也可以返回一个新的对象来替换传入的对象。
type ModifyRsbuildConfigUtils = {
mergeRsbuildConfig: typeof mergeRsbuildConfig;
};
function ModifyRsbuildConfig(
callback: (
config: RsbuildConfig,
utils: ModifyRsbuildConfigUtils,
) => MaybePromise<RsbuildConfig | void>,
): void;
const myPlugin = () => ({
setup: (api) => {
api.modifyRsbuildConfig((config) => {
config.html ||= {};
config.html.title = 'My Default Title';
});
},
});
- 示例: 通过
mergeRsbuildConfig
合并配置多个对象,并返回合并后的对象。
import type { RsbuildConfig } from '@rsbuild/core';
const myPlugin = () => ({
setup: (api) => {
api.modifyRsbuildConfig((userConfig, { mergeRsbuildConfig }) => {
const extraConfig: RsbuildConfig = {
source: {
// ...
},
output: {
// ...
},
};
// extraConfig 会覆盖 userConfig 里的字段,
// 如果你不希望覆盖 userConfig,可以调整为 `mergeRsbuildConfig(extraConfig, userConfig)`
return mergeRsbuildConfig(userConfig, extraConfig);
});
},
});
modifyRspackConfig
修改最终的 Rspack 配置对象,你可以直接修改传入的 config 对象,也可以返回一个新的对象来替换传入的对象。
type ModifyRspackConfigUtils = {
env: NodeEnv;
isDev: boolean;
isProd: boolean;
target: RsbuildTarget;
isServer: boolean;
isWebWorker: boolean;
rspack: Rspack;
};
function ModifyRspackConfig(
callback: (
config: RspackConfig,
utils: ModifyRspackConfigUtils,
) => Promise<RspackConfig | void> | RspackConfig | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.modifyRspackConfig((config, utils) => {
if (utils.env === 'development') {
config.devtool = 'eval-cheap-source-map';
}
});
},
});
modifyBundlerChain
rspack-chain
是一个用于配置 Rspack 的工具库。它提供了链式 API,使得配置 Rspack 变得更加灵活。通过使用 rspack-chain
,你可以更方便地修改和扩展 Rspack 配置,而不需要直接操作复杂的配置对象。
modifyBundlerChain
用于调用 rspack-chain 来修改 Rspack 的配置。
type ModifyBundlerChainUtils = {
env: NodeEnv;
isDev: boolean;
isProd: boolean;
target: RsbuildTarget;
isServer: boolean;
isWebWorker: boolean;
CHAIN_ID: ChainIdentifier;
HtmlPlugin: typeof import('html-webpack-plugin');
bundler: {
BannerPlugin: rspack.BannerPlugin;
DefinePlugin: rspack.DefinePlugin;
IgnorePlugin: rspack.IgnorePlugin;
ProvidePlugin: rspack.ProvidePlugin;
HotModuleReplacementPlugin: rspack.HotModuleReplacementPlugin;
};
};
function ModifyBundlerChain(
callback: (
chain: RspackChain,
utils: ModifyBundlerChainUtils,
) => Promise<void> | void,
): void;
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
const myPlugin = () => ({
setup: (api) => {
api.modifyBundlerChain((chain, utils) => {
if (utils.env === 'development') {
chain.devtool('eval');
}
chain.plugin('bundle-analyze').use(BundleAnalyzerPlugin);
});
},
});
modifyHTMLTags
修改注入到 HTML 中的标签。
type HtmlBasicTag = {
// 标签名
tag: string;
// 标签的属性
attrs?: Record<string, string | boolean | null | undefined>;
// 标签的 innerHTML
children?: string;
};
type HTMLTags = {
// 插入到 <head> 的标签组
headTags: HtmlBasicTag[];
// 插入到 <body> 的标签组
bodyTags: HtmlBasicTag[];
};
type Context = {
/**
* Rspack 的 Compilation 对象
*/
compilation: Rspack.Compilation;
/**
* 静态资源的 URL 前缀
* @example 'https://example.com/'
*/
assetPrefix: string;
/**
* HTML 文件的名称,相对于 dist 目录
* @example 'index.html'
*/
filename: string;
};
function ModifyHTMLTags(
callback: (tags: HTMLTags, context: Context) => MaybePromise<HTMLTags>,
): void;
const myPlugin = () => ({
setup: (api) => {
api.modifyHTMLTags(({ headTags, bodyTags }) => {
headTags.push({
tag: 'script',
attrs: { src: 'https://example.com/foo.js' },
});
bodyTags.push({
tag: 'script',
children: 'console.log("hello world!");',
});
return { headTags, bodyTags };
});
},
});
onBeforeCreateCompiler
onBeforeCreateCompiler
是在创建底层 Compiler 实例前触发的回调函数,当你执行 rsbuild.startDevServer
、rsbuild.build
或 rsbuild.createCompiler
时,都会调用此钩子。
你可以通过 bundlerConfigs
参数获取到 Rspack 配置数组,数组中可能包含一份或多份 Rspack 配置,这取决于 Rsbuild output.targets 配置的值。
function OnBeforeCreateCompiler(
callback: (params: {
bundlerConfigs: WebpackConfig[] | RspackConfig[];
}) => Promise<void> | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
console.log('the bundler config is ', bundlerConfigs);
});
},
});
onAfterCreateCompiler
onAfterCreateCompiler
是在创建 Compiler 实例后、执行构建前触发的回调函数,当你执行 rsbuild.startDevServer
、rsbuild.build
或 rsbuild.createCompiler
时,都会调用此钩子。
你可以通过 compiler
参数获取到 Compiler 实例对象:
function OnAfterCreateCompiler(callback: (params: {
compiler: Compiler | MultiCompiler;
}) => Promise<void> | void;): void;
const myPlugin = () => ({
setup: (api) => {
api.onAfterCreateCompiler(({ compiler }) => {
console.log('the compiler is ', compiler);
});
},
});
Build Hooks
onBeforeBuild
onBeforeBuild
是在执行生产环境构建前触发的回调函数。
你可以通过 bundlerConfigs
参数获取到 Rspack 配置数组,数组中可能包含一份或多份 Rspack 配置,这取决于 Rsbuild output.targets 配置的值。
function OnBeforeBuild(
callback: (params: {
bundlerConfigs?: WebpackConfig[] | RspackConfig[];
}) => Promise<void> | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.onBeforeBuild(({ bundlerConfigs }) => {
console.log('the bundler config is ', bundlerConfigs);
});
},
});
onAfterBuild
onAfterBuild
是在执行生产环境构建后触发的回调函数,你可以通过 stats 参数获取到构建结果信息:
另外,在 watch 模式下你可以通过 isFirstCompile
来判断是否为首次构建。
function OnAfterBuild(
callback: (params: {
isFirstCompile: boolean;
stats?: Stats | MultiStats;
}) => Promise<void> | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.onAfterBuild(({ isFirstCompile, stats }) => {
console.log(stats?.toJson(), isFirstCompile);
});
},
});
Dev Hooks
onBeforeStartDevServer
在启动开发服务器前调用。
function OnBeforeStartDevServer(callback: () => Promise<void> | void): void;
const myPlugin = () => ({
setup: (api) => {
api.onBeforeStartDevServer(() => {
console.log('before start!');
});
},
});
onAfterStartDevServer
在启动开发服务器后调用。你可以通过 port
参数获得开发服务器监听的端口号,通过 routes
获得页面路由信息。
type Routes = Array<{
entryName: string;
pathname: string;
}>;
function OnAfterStartDevServer(
callback: (params: { port: number; routes: Routes }) => Promise<void> | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.onAfterStartDevServer(({ port, routes }) => {
console.log('this port is: ', port);
console.log('this routes is: ', routes);
});
},
});
onDevCompileDone
在每次开发环境构建结束后调用,你可以通过 isFirstCompile
来判断是否为首次构建。
function OnDevCompileDone(
callback: (params: {
isFirstCompile: boolean;
stats: Stats | MultiStats;
}) => Promise<void> | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.onDevCompileDone(({ isFirstCompile }) => {
if (isFirstCompile) {
console.log('first compile!');
} else {
console.log('re-compile!');
}
});
},
});
onCloseDevServer
关闭开发服务器时调用。
function onCloseDevServer(callback: () => Promise<void> | void): void;
rsbuild.onCloseDevServer(async () => {
console.log('close dev server!');
});
Preview Hooks
onBeforeStartProdServer
在启动生产预览服务器前调用。
function OnBeforeStartProdServer(callback: () => Promise<void> | void): void;
const myPlugin = () => ({
setup: (api) => {
api.onBeforeStartProdServer(() => {
console.log('before start!');
});
},
});
onAfterStartProdServer
在启动生产预览服务器后调用,你可以通过 port
参数获得生产服务器监听的端口号,通过 routes
获得页面路由信息。
type Routes = Array<{
entryName: string;
pathname: string;
}>;
function OnAfterStartProdServer(
callback: (params: { port: number; routes: Routes }) => Promise<void> | void,
): void;
const myPlugin = () => ({
setup: (api) => {
api.onAfterStartProdServer(({ port, routes }) => {
console.log('this port is: ', port);
console.log('this routes is: ', routes);
});
},
});
Other Hooks
onExit
在进程即将退出时调用,这个钩子只能执行同步代码。
function OnExit(callback: () => void): void;
const myPlugin = () => ({
setup: (api) => {
api.onExit(() => {
console.log('exit!');
});
},
});