Rsbuild 插件开发指南
插件开发
启动一个基本的插件项目:
import { RsbuildPlugin } from '@rsbuild/core';
export default function plugin(): RsbuildPlugin {
return {
name: 'plugin',
setup(api) {
// api 对象上的方法即是 plugin hooks,存在的方法可以再这里进行查找
// https://rsbuild.rs/plugins/dev/hooks
}
};
}
这时候在 rsbuild 配置(rsbuild.config.ts)中,就可以引入这个插件了:
import { defineConfig } from '@rsbuild/core';
import customPlugin from './plugin';
export default defineConfig({
plugins: [customPlugin()],
});
为插件增加配置选项 PluginOptions
如下,增加一个 PluginOptions 的 inteface,可以作为参数传给 plugin 函数。建议同时导出 PluginOptions 类型,方便插件使用者阅读类型信息
import { RsbuildPlugin } from '@rsbuild/core';
export interface PluginOptions {
foo: string;
}
export default function plugin(options: PluginOptions): RsbuildPlugin {
return {
name: 'plugin',
setup(api) {
// 这里可以通过 options 拿到用户传入的配置
console.log(options.foo);
}
}
}
了解插件的 API
Rsbuild api 一共提供了以下属性,这些 hook 会按照顺序执行。
- modifyRsbuildConfig
- modifyEnvironmentConfig
- onBeforeStartDevServer
- modifyBundlerChain
- modifyRspackConfig
- onBeforeCreateCompiler
- onAfterCreateCompiler
- onBeforeEnvironmentCompile
- onAfterStartDevServer
- modifyHTMLTags
- modifyHTML
- onAfterEnvironmentCompile
- onDevCompileDone
- onCloseDevServer
- onExit
一些注意事项:
- 真实的 Rsbuild 实例会在
modifyRsbuildConfig
modifyEnvironmentConfig
onBeforeStartDevServer
之后创建,所以在这三个 API 内并没有明确的 mode 是 development 还是 production。在这三个 API 内可以通过 process.node.NODE_ENV
来判断是否为 development,在此之后的 API 中可以通过 hooks 参数中的 isDev isProd 来判断
- Rsbuild 依赖的 Rspack 实例是在
modifyRsbuildConfig
modifyEnvironmentConfig
onBeforeStartDevServer
modifyRspackConfig
modifyBundlerChain
onBeforeCreateCompiler
这些 API 之后创建的。所以在此之后的 API 才可以有 rspack 的实例
判断环境是 development 还是 production
可以通过 api.modifyRsbuildConfig 方法拿到 Rsbuild 的配置,然后根据配置的 mode 来判断环境:
import { RsbuildPlugin } from '@rsbuild/core';
export default function plugin(): RsbuildPlugin {
return {
name: 'plugin',
setup(api) {
// 在 modifyRsbuildConfig 中还没有最终的 mode
api.modifyRsbuildConfig((config) => {
const isDev = process.env.NODE_ENV === 'development';
const isProd = process.env.NODE_ENV === 'production';
});
// 在 modifyRspackConfig 中可以通过 isDev 和 isProd 来判断环境
api.modifyRspackConfig((config, { isDev, isProd }) => {
if (isDev) {
console.log('development');
} else if (isProd) {
console.log('production');
}
});
}
}
}
修改 Rsbuild 的基本配置
思路
- 通过阅读 RsbuildConfig 了解哪个配置项目可以满足插件的需求
- 通过
api.modifyRsbuildConfig
方法修改 Rsbuild 的基本配置
例子 1: 修改输出目录
例如,我们需要开发一个插件,修改输出目录的位置:
- 在 Rsbuild 配置中了解可以修改输出目录的配置项目,找到为 output.distPath 可以参考文档
- 编写插件,通过
api.modifyRsbuildConfig
方法修改输出目录的位置,代码示例如下:
import { RsbuildPlugin } from '@rsbuild/core';
interface OutputOptions {
path: string;
}
export default function plugin(options: OutputOptions): RsbuildPlugin {
return {
name: 'plugin',
setup(api) {
if(options.path) {
// userConfig 即为 Rsbuild 的配置
// 可以在这里查看配置的全部内容 https://rsbuild.rs/config/
api.modifyRsbuildConfig((userConfig, { mergeRsbuildConfig }) => {
const outputConfig: RsbuildConfig = {
output: {
distPath: {
root: options.path,
}
},
};
// outputConfig 会覆盖用户的配置
// 如果不希望覆盖用户的配置,可以使用 `mergeRsbuildConfig` 方法反过来传递
// 例如: mergeRsbuildConfig(outputConfig, userConfig)
return mergeRsbuildConfig(userConfig, outputConfig);
});
}
}
};
}
例子 2: 自定义页面入口
例如,我们需要开发一个插件,自定义页面入口:
- 在 Rsbuild 配置中了解可以修改页面入口的配置项目,找到为 source.entry 可以参考文档
- 编写插件,通过
api.modifyRsbuildConfig
方法修改页面入口的位置,代码示例如下:
import { RsbuildPlugin } from '@rsbuild/core';
interface EntryOptions {
entry: string;
}
export default function plugin(options: EntryOptions): RsbuildPlugin {
return {
name: 'rsbuild-source-plugin',
setup(api) {
if(options.entry) {
api.modifyRsbuildConfig((userConfig, { mergeRsbuildConfig }) => {
let entry = "./src/index.ts"; // config you own entry, custom your logic here
const sourceConfig: RsbuildConfig = {
source:{
entry: entry || options.entry,
},
};
return mergeRsbuildConfig(userConfig, sourceConfig);
});
}
}
};
}
自定义 DevServer 的行为
可以通过 onBeforeStartDevServer 来自定义 DevServer 的行为。
例如,我们需要自定义 DevServer 来处理一些请求,代码示例如下:
import { RsbuildPlugin } from '@rsbuild/core';
import { RequestHandler } from 'express';
type DevServerOptions = Record<string, string>;
export default function plugin(options: DevServerOptions): RsbuildPlugin {
return {
name: 'plugin',
setup(api) {
api.onBeforeStartDevServer(({ server }) => {
server.middlewares.use((req, res, next) => {
const urls = Object.keys(options);
if(urls.includes(req.url)) {
res.end(options[req.url]);
}else{
next();
}
});
});
},
};
}
该插件的使用例子:
import staticContent from './plugin';
export default {
plugins: [
staticContent({
'/json': '{"name": "rsbuild"}',
})
]
}
插件的日志打印
默认情况下插件可以直接使用 console.log
和 console.error
等标准方法进行日志输出。如果你希望打印跟 Rsbuild 主题更接近的 log 可以使用 logger。
import { logger } from "@rsbuild/core";
logger.log("hello world");
自定义 resolver
当插件有需求要自定义 resolver 的行为时,可以使用 @rspack/resolver 来创建新的 resolver,可以在这里了解更多的信息
import { ResolverFactory } from "@rspack/resolver";
const resolver = new ResolverFactory({
alias: [],
mainFields: ["main", "module"],
});
const indexJsPath = resolver.async(__dirname, "./index.js").path; // resolve specifier at an absolute path to a directory.