Rsbuild Instance
本章节描述了 Rsbuild 实例对象上所有的属性和方法。
rsbuild.context
rsbuild.context
是一个只读对象,提供一些上下文信息。
context.version
当前使用的 @rsbuild/core
版本。
context.rootPath
当前执行构建的根路径,对应调用 createRsbuild 时传入的 cwd
选项。
context.distPath
构建产物输出目录的绝对路径,对应 RsbuildConfig
中的 output.distPath.root 配置项。
当有多个环境时,Rsbuild 会尝试获取所有环境的父 distPath 作为 context.distPath
。
如果要获取指定环境的输出目录的绝对路径,建议使用 environment.distPath。
context.cachePath
构建过程中生成的缓存文件所在的绝对路径。
context.devServer
Dev server 相关信息,包含了当前 dev server 的 hostname 和端口号。
type DevServer = {
hostname: string;
port: number;
};
context.bundlerType
当前执行构建的构建工具类型。
type bundlerType = 'rspack' | 'webpack';
Rsbuild 内部支持切换到 webpack 进行对照测试,因此提供了该字段进行区分,通常你不需要使用此字段。
rsbuild.environments
target
构建产物类型,对应 Rsbuild 的 output.target 配置。
type RsbuildTarget = 'web' | 'node' | 'web-worker';
tsconfigPath
tsconfig.json 文件的绝对路径,若项目中不存在 tsconfig.json 文件,则为 undefined
。
type TsconfigPath = string | undefined;
rsbuild.build
调用 build 方法时,会执行一次生产模式构建。
type BuildOptions = {
/**
* 是否监听文件变化并重新构建
*
* @default false
*/
watch?: boolean;
/**
* 使用自定义的 Rspack Compiler 对象
*/
compiler?: Compiler | MultiCompiler;
};
function Build(options?: BuildOptions): Promise<{
/**
* Rspack 的 [stats](https://rspack.dev/api/javascript-api/stats) 对象。
*/
stats?: Rspack.Stats | Rspack.MultiStats;
/**
* 停止监听文件变化。
*/
close: () => Promise<void>;
}>;
import { logger } from '@rsbuild/core';
// Example 1: run build
await rsbuild.build();
// Example 2: build and handle the error
try {
await rsbuild.build();
} catch (err) {
logger.error('Failed to build.');
logger.error(err);
process.exit(1);
}
// Example 3: build and get all stats
const { stats } = await rsbuild.build();
if (stats) {
const { assets } = stats.toJson({ assets: true });
console.log(assets);
}
监听文件变化
如果需要自动监听文件变化并重新执行构建,可以将 watch
参数设置为 true
。
await rsbuild.build({
watch: true,
});
在 watch 模式下,rsbuild.build()
会返回一个 close
方法,调用该方法将会结束监听:
const result = await rsbuild.build({
watch: true,
});
await result.close();
Stats 对象
在非 watch 模式下,rsbuild.build()
会返回一个 Rspack 的 stats 对象:
const result = await rsbuild.build();
console.log(result.stats);
自定义 Compiler
个别情况下,你可能希望使用自定义的 compiler:
import { rspack } from '@rsbuild/core';
const compiler = rspack({
// ...
});
await rsbuild.build({
compiler,
});
rsbuild.startDevServer
启动本地 dev server。
type StartDevServerOptions = {
/**
* 使用自定义的 Rspack Compiler 对象
*/
compiler?: Compiler | MultiCompiler;
/**
* 是否在启动时静默获取端口号,不输出任何日志
* @default false
*/
getPortSilently?: boolean;
};
type StartServerResult = {
urls: string[];
port: number;
server: Server;
};
function StartDevServer(
options?: StartDevServerOptions,
): Promise<StartServerResult>;
启动 dev server:
import { logger } from '@rsbuild/core';
// Start dev server
await rsbuild.startDevServer();
// Start dev server and handle the error
try {
await rsbuild.startDevServer();
} catch (err) {
logger.error('Failed to start dev server.');
logger.error(err);
process.exit(1);
}
成功启动 dev server 后,可以看到以下日志信息:
➜ Local: http://localhost:3000
➜ Network: http://192.168.0.1:3000
startDevServer
会返回以下参数:
urls
:访问 dev server 的 URLs
port
实际监听的端口号
server
:Server 实例对象
const { urls, port, server } = await rsbuild.startDevServer();
console.log(urls); // ['http://localhost:3000', 'http://192.168.0.1:3000']
console.log(port); // 3000
// 关闭 dev server
await server.close();
自定义 Compiler
个别情况下,你可能希望使用自定义的 compiler:
import { rspack } from '@rsbuild/core';
const compiler = rspack({
// ...
});
await rsbuild.startDevServer({
compiler,
});
静默获取端口号
某些情况下,默认启动的端口号已经被占用,此时 Rsbuild 会自动递增端口号,直至找到一个可用端口。这个过程会输出提示日志,如果你不希望这段日志,可以将 getPortSilently
设置为 true
。
await rsbuild.startDevServer({
getPortSilently: true,
});
rsbuild.createDevServer
Rsbuild 配备了一个内置的开发服务器,当你执行 rsbuild dev
时,将启动 Rsbuild dev server,并提供页面预览、路由、模块热更新等功能。
如果你希望将 Rsbuild dev server 集成到自定义的 server 中,可以通过该方法获取 dev server 的实例方法,按需进行调用。
type EnvironmentAPI = {
[name: string]: {
/**
* 获取当前环境的构建信息
*/
getStats: () => Promise<Stats>;
/**
* 在服务端加载并执行构建产物
*
* @param entryName - 入口名称,和 Rsbuild source.entry 的某一个 key 值对应
* @returns 入口模块的返回值
*/
loadBundle: <T = unknown>(entryName: string) => Promise<T>;
/**
* 获取编译后的 HTML 模版内容
*/
getTransformedHtml: (entryName: string) => Promise<string>;
};
};
type RsbuildDevServer = {
/**
* 监听 Rsbuild server
* 当你使用自定义 server 时,不需要调用该方法
*/
listen: () => Promise<{
port: number;
urls: string[];
server: {
close: () => Promise<void>;
};
}>;
/**
* Rsbuild server 提供的 environment API
*/
environments: EnvironmentAPI;
/**
* 解析后的端口号
* 默认情况下,Rsbuild Server 会监听 `3000` 端口,如果端口被占用,则自动递增端口号
*/
port: number;
/**
* `connect` 实例
* 可用于向 dev server 附加自定义中间件
*/
middlewares: Connect.Server;
/**
* 通知 Rsbuild 自定义 Server 已启动
* Rsbuild 会在此阶段触发 `onAfterStartDevServer` 钩子
*/
afterListen: () => Promise<void>;
/**
* 激活 socket 连接
* 这确保了 HMR 正常工作
*/
connectWebSocket: (options: { server: HTTPServer }) => void;
/**
* 关闭 Rsbuild server
*/
close: () => Promise<void>;
/**
* 打印 server URLs
*/
printUrls: () => void;
/**
* 启动服务器后,在浏览器中打开 URL
*/
open: () => Promise<void>;
};
type CreateDevServerOptions = {
/**
* 自定义 Compiler 对象
*/
compiler?: Compiler | MultiCompiler;
/**
* 是否在启动时静默获取端口号,不输出任何日志
* @default false
*/
getPortSilently?: boolean;
/**
* 是否触发 Rsbuild 编译
* @default true
*/
runCompile?: boolean;
};
function CreateDevServer(
options?: CreateDevServerOptions,
): Promise<RsbuildDevServer>;
下面是一个在 express 中集成 Rsbuild DevServer 的例子:
import { createRsbuild } from '@rsbuild/core';
import express from 'express';
export async function startDevServer() {
// 初始化 Rsbuild
const rsbuild = await createRsbuild({});
const app = express();
// 创建 Rsbuild DevServer 实例
const rsbuildServer = await rsbuild.createDevServer();
// 使用 Rsbuild 的内置中间件
app.use(rsbuildServer.middlewares);
const httpServer = app.listen(rsbuildServer.port, async () => {
// 通知 Rsbuild 自定义 Server 已启动
await rsbuildServer.afterListen();
});
rsbuildServer.connectWebSocket({ server: httpServer });
}
详细使用情况可参考:示例。
如果你希望直接使用 Rsbuild DevServer 启动项目,可以直接使用 Rsbuild - startDevServer 方法。 startDevServer
实际上是以下代码的语法糖:
const server = await rsbuild.createDevServer();
await server.listen();
connectWebSocket
Rsbuild 内置了 WebSocket 处理器以支持 HMR 功能:
- 当用户通过浏览器访问页面时,会自动向服务器发起 WebSocket 连接请求。
- Rsbuild 开发服务器检测到连接请求后,会指示内置的 WebSocket 处理器进行处理。
- 浏览器与 Rsbuild WebSocket 处理器成功建立连接后,便可进行实时通信。
- 每次重新编译完成后,Rsbuild WebSocket 处理器会通知浏览器。随后,浏览器向开发服务器发送
hot-update.(js|json)
请求,以加载编译后的新模块。
当你使用自定义的 server 时,可能会遇到 HMR 连接报错的问题,这是因为自定义的 server 没有将 WebSocket 连接请求转发给 Rsbuild 的 WebSocket 处理器。此时需要通过 connectWebSocket
方法已使 Rsbuild 能够感知并处理来自浏览器的 WebSocket 连接请求。
const rsbuildServer = await rsbuild.createDevServer();
const httpServer = app.listen(rsbuildServer.port);
rsbuildServer.connectWebSocket({ server: httpServer });
rsbuild.preview
在本地启动 server 来预览生产模式构建的产物,需要在 rsbuild.build 方法之后执行。
type PreviewOptions = {
/**
* 是否在启动时静默获取端口号,不输出任何日志
* @default false
*/
getPortSilently?: boolean;
/**
* 是否检查 dist 目录存在且不为空
* @default true
*/
checkDistDir?: boolean;
};
type StartServerResult = {
urls: string[];
port: number;
server: {
close: () => Promise<void>;
};
};
function preview(options?: PreviewOptions): Promise<StartServerResult>;
启动 Server:
import { logger } from '@rsbuild/core';
// Start preview server
await rsbuild.preview();
// Start preview server and handle the error
try {
await rsbuild.preview();
} catch (err) {
logger.error('Failed to start preview server.');
logger.error(err);
process.exit(1);
}
preview
会返回以下参数:
urls
:访问 Server 的 URLs
port
实际监听的端口号
server
:Server 实例对象
const { urls, port, server } = await rsbuild.preview();
console.log(urls); // ['http://localhost:3000', 'http://192.168.0.1:3000']
console.log(port); // 3000
// 关闭 Server
await server.close();
rsbuild.createCompiler
创建一个 Rspack Compiler 实例;如果本次构建存在多个 environments,则返回值为 MultiCompiler
。
function CreateCompiler(): Promise<Compiler | MultiCompiler>;
const compiler = await rsbuild.createCompiler();
大部分场景下,你不需要使用该 API,除非需要进行自定义 dev server 等高级操作。
rsbuild.addPlugins
注册一个或多个 Rsbuild 插件,可以被多次调用。
该方法需要在开始编译前调用,如果在开始编译之后调用,则不会影响编译结果。
type AddPluginsOptions = { before?: string; environment?: string };
function AddPlugins(
plugins: Array<RsbuildPlugin | Falsy>,
options?: AddPluginsOptions,
): void;
rsbuild.addPlugins([pluginFoo(), pluginBar()]);
// 在 bar 插件之前插入
rsbuild.addPlugins([pluginFoo()], { before: 'bar' });
// 为 node 环境添加插件
rsbuild.addPlugins([pluginFoo()], { environment: 'node' });
rsbuild.getPlugins
获取当前 Rsbuild 实例中注册的所有 Rsbuild 插件。
function GetPlugins(): RsbuildPlugin[];
console.log(rsbuild.getPlugins());
rsbuild.removePlugins
移除一个或多个 Rsbuild 插件,可以被多次调用。
该方法需要在开始编译前调用,如果在开始编译之后调用,则不会影响编译结果。
function RemovePlugins(pluginNames: string[]): void;
// 添加插件
const pluginFoo = pluginFoo();
rsbuild.addPlugins(pluginFoo);
// 移除插件
rsbuild.removePlugins([pluginFoo.name]);
rsbuild.isPluginExists
判断某个插件是否已经被注册。
function IsPluginExists(pluginName: string): boolean;
rsbuild.addPlugins([pluginFoo()]);
rsbuild.isPluginExists(pluginFoo().name); // true
rsbuild.initConfigs
initConfigs 方法用于初始化 Rsbuild 内部的配置,并返回 Rsbuild 内部生成的 Rspack 配置。
通常你不需要调用 initConfigs 方法,因为调用 rsbuild.build、rsbuild.startDevServer 等方法时会自动调用 initConfigs。
function InitConfigs(): Promise<{
rspackConfigs: Rspack.Configuration[];
}>;
const { rspackConfigs } = await rsbuild.initConfigs();
console.log(rspackConfigs);
rsbuild.inspectConfig
inspectConfig 方法通常用于调试 Rsbuild 内部的配置,它会返回 Rsbuild 内部生成的 Rsbuild 配置和 Rspack 配置,将它们序列化为字符串,并支持写入到磁盘上。
如果你需要在构建过程中查看 Rsbuild 和 Rspack 配置,可以使用 调试模式,也可以通过 onBeforeBuild、onBeforeCreateCompile 等 hooks 来获取。
type InspectConfigOptions = {
// 查看指定环境下的配置
// 默认为 "development",可以设置为 "production"
mode?: RsbuildMode;
// 是否开启冗余模式,展示配置中函数的完整内容
// 默认为 `false`
verbose?: boolean;
// 指定输出路径
// 默认为 `output.distPath.root` 的值
outputPath?: string;
// 是否将结果写入到磁盘中
// 默认为 `false`
writeToDisk?: boolean;
};
async function InspectConfig(options?: InspectConfigOptions): Promise<{
rsbuildConfig: string;
bundlerConfigs: string[];
environmentConfigs: string[];
origin: {
rsbuildConfig: RsbuildConfig;
environmentConfigs: Record<string, EnvironmentConfig>;
bundlerConfigs: BundlerConfigs[];
};
}>;
示例
拿到字符串格式的 configs 内容:
const { rsbuildConfig, bundlerConfigs } = await rsbuild.inspectConfig();
console.log(rsbuildConfig, bundlerConfigs);
直接将配置内容写入到磁盘上:
await rsbuild.inspectConfig({
writeToDisk: true,
});
输出路径
你可以通过 outputPath
来设置输出目录,默认为 output.distPath.root 的值。
当 outputPath
是一个相对路径时,会相对于 output.distPath.root
的值进行拼接。你也可以将 outputPath
设置为一个绝对路径,此时会直接将文件写入到该路径下。比如:
import path from 'node:path';
await rsbuild.inspectConfig({
writeToDisk: true,
outputPath: path.join(__dirname, 'custom-dir'),
});
rsbuild.onBeforeCreateCompiler
onBeforeCreateCompiler
是在创建底层 Compiler 实例前触发的回调函数,当你执行 rsbuild.startDevServer
、rsbuild.build
或 rsbuild.createCompiler
时,都会调用此钩子。
你可以通过 bundlerConfigs
参数获取到 Rspack 配置数组,数组中可能包含一份或多份 Rspack 配置,这取决于是否配置了多个 environments。
function OnBeforeCreateCompiler(
callback: (params: {
bundlerConfigs: Rspack.Configuration[];
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onBeforeCreateCompiler(({ bundlerConfigs }) => {
console.log('the Rspack config is ', bundlerConfigs);
});
rsbuild.onAfterCreateCompiler
onAfterCreateCompiler
是在创建 Compiler 实例后、执行构建前触发的回调函数,当你执行 rsbuild.startDevServer
、rsbuild.build
或 rsbuild.createCompiler
时,都会调用此钩子。
你可以通过 compiler
参数获取到 Compiler 实例对象:
function OnAfterCreateCompiler(callback: (params: {
compiler: Compiler | MultiCompiler;
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void;): void;
rsbuild.onAfterCreateCompiler(({ compiler }) => {
console.log('the compiler is ', compiler);
});
rsbuild.onBeforeBuild
onBeforeBuild
是在执行生产模式构建前触发的回调函数。
你可以通过 bundlerConfigs
参数获取到 Rspack 配置数组,数组中可能包含一份或多份 Rspack 配置,这取决于是否配置了多个 environments。
另外,你可以通过 isWatch
判断是否是 watch 模式,并在 watch 模式下通过 isFirstCompile
来判断是否为首次构建。
function OnBeforeBuild(
callback: (params: {
isWatch: boolean;
isFirstCompile: boolean;
bundlerConfigs?: Rspack.Configuration[];
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onBeforeBuild(({ bundlerConfigs }) => {
console.log('the Rspack config is ', bundlerConfigs);
});
rsbuild.onAfterBuild
onAfterBuild
是在执行生产模式构建后触发的回调函数,你可以通过 stats 参数获取到构建结果信息。
另外,你可以通过 isWatch
判断是否是 watch 模式,并在 watch 模式下通过 isFirstCompile
来判断是否为首次构建。
function OnAfterBuild(
callback: (params: {
isFirstCompile: boolean;
isWatch: boolean;
stats?: Stats | MultiStats;
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onAfterBuild(({ stats }) => {
console.log(stats?.toJson());
});
rsbuild.onBeforeStartDevServer
在启动开发服务器前调用。
function OnBeforeStartDevServer(
callback: (params: {
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onBeforeStartDevServer(() => {
console.log('before start!');
});
rsbuild.onAfterStartDevServer
在启动开发服务器后调用。你可以通过 port
参数获得开发服务器监听的端口号,通过 routes
获得页面路由信息。
type Routes = Array<{
entryName: string;
pathname: string;
}>;
function OnAfterStartDevServer(
callback: (params: {
port: number;
routes: Routes;
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onAfterStartDevServer(({ port, routes }) => {
console.log('this port is: ', port);
console.log('this routes is: ', routes);
});
rsbuild.onCloseDevServer
关闭开发服务器时调用。
function onCloseDevServer(callback: () => Promise<void> | void): void;
rsbuild.onCloseDevServer(async () => {
console.log('close dev server!');
});
rsbuild.onBeforeStartProdServer
在启动生产预览服务器前调用。
function OnBeforeStartProdServer(callback: () => Promise<void> | void): void;
rsbuild.onBeforeStartProdServer(() => {
console.log('before start!');
});
rsbuild.onAfterStartProdServer
在启动生产预览服务器后调用,你可以通过 port
参数获得生产服务器监听的端口号,通过 routes
获得页面路由信息。
type Routes = Array<{
entryName: string;
pathname: string;
}>;
function OnAfterStartProdServer(
callback: (params: {
port: number;
routes: Routes;
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onAfterStartProdServer(({ port, routes }) => {
console.log('this port is: ', port);
console.log('this routes is: ', routes);
});
rsbuild.onDevCompileDone
在每次开发模式构建结束后调用,你可以通过 isFirstCompile
来判断是否为首次构建。
function OnDevCompileDone(
callback: (params: {
isFirstCompile: boolean;
stats: Stats | MultiStats;
environments: Record<string, EnvironmentContext>;
}) => Promise<void> | void,
): void;
rsbuild.onDevCompileDone(({ isFirstCompile }) => {
if (isFirstCompile) {
console.log('first compile!');
} else {
console.log('re-compile!');
}
});
rsbuild.onExit
在进程即将退出时调用,这个钩子只能执行同步代码。
function OnExit(callback: () => void): void;
rsbuild.onExit(() => {
console.log('exit!');
});
rsbuild.getRsbuildConfig
获取 Rsbuild 配置。
type GetRsbuildConfig = {
(): Readonly<RsbuildConfig>;
(type: 'original' | 'current'): Readonly<RsbuildConfig>;
(type: 'normalized'): NormalizedConfig;
};
你可以通过 type
参数来指定读取的 Rsbuild 配置类型:
// 获取用户定义的原始 Rsbuild 配置。
getRsbuildConfig('original');
// 获取当前的 Rsbuild 配置。
// 在 Rsbuild 的不同执行阶段,该配置的内容会发生变化。
// 比如 `modifyRsbuildConfig` 钩子执行后会修改当前 Rsbuild 配置的内容。
getRsbuildConfig('current');
// 获取归一化后的 Rsbuild 配置。
// 该方法必须在 `modifyRsbuildConfig` 钩子执行完成后才能被调用。
// 等价于 `getNormalizedConfig` 方法。
getRsbuildConfig('normalized');
rsbuild.onBeforeBuild(() => {
const config = rsbuild.getRsbuildConfig();
console.log(config.html?.title);
});
rsbuild.getNormalizedConfig
获取归一化后的全部 Rsbuild 配置,或指定环境的 Rsbuild 配置。该方法必须在 modifyRsbuildConfig 钩子执行完成后才能被调用。
相较于 getRsbuildConfig
方法,该方法返回的配置经过了归一化处理,配置的类型定义会得到收敛,比如 config.html
的 undefined
类型将被移除。
推荐优先使用该方法获取配置。
/** 获取指定环境的 Rsbuild 配置 */
function GetNormalizedConfig(options: {
environment: string;
}): Readonly<NormalizedEnvironmentConfig>;
/** 获取全部的 Rsbuild 配置 */
function GetNormalizedConfig(): Readonly<NormalizedConfig>;
rsbuild.onBeforeBuild(() => {
const config = rsbuild.getNormalizedConfig();
console.log(config.html.title);
});