Builder Instance
This section describes all the properties and methods on the Builder instance object.
builder.context
builder.context
is a read-only object that provides some context infos.
builder.context.entry
The entry object, corresponding to the entry
option of createBuilder
method.
type BuilderEntry = Record<string, string | string[]>;
builder.context.target
Build target type, corresponding to the target
option of createBuilder
method.
type BuilderTarget = 'web' | 'node' | 'modern-web' | 'web-worker';
type Context = {
target: BuilderTarget | BuilderTarget[];
};
builder.context.rootPath
The root path of current build, corresponding to the cwd
option of createBuilder
method.
builder.context.srcPath
The absolute path to the src directory.
builder.context.distPath
The absolute path of the output directory, corresponding to the output.distPath.root
config in BuilderConfig
.
builder.context.cachePath
The absolute path of the build cache files.
builder.context.configPath
The absolute path to the framework config file, corresponding to the configPath
option of createBuilder
method.
type ConfigPath = string | undefined;
builder.context.tsconfigPath
The absolute path of the tsconfig.json file, or undefined
if the tsconfig.json file does not exist in current project.
type TsconfigPath = string | undefined;
builder.context.framework
The name of the framework, a unique identifier, the default value is 'modern.js'
.
type Framework = string | undefined;
builder.context.devServer
Dev Server information, including the current Dev Server hostname and port number.
type DevServer = {
hostname: string;
port: number;
};
builder.context.bundlerType
The bundler type of current build.
type bundlerType = 'webpack' | 'rspack';
builder.build
Perform a production build.
type BuildOptions = {
mode?: 'development' | 'production';
watch?: boolean;
// custom Compiler object
compiler?: Compiler | MultiCompiler;
};
function Build(options?: BuildOptions): Promise<void>;
Development environment build
If you need to perform a development build, you can set the mode
option to 'development'
.
await builder.build({
mode: 'development',
});
Monitor file changes
If you need to watch file changes and re-build, you can set the watch
option to true
.
await builder.build({
watch: true,
});
Custom Compiler
In some cases, you may want to use a custom compiler:
const compiler = webpack({
// ...
});
await builder.build({
compiler,
});
builder.startDevServer
Start the local Dev Server, based on the Modern.js Dev Server.
type StartDevServerOptions = {
// Whether to output URL infos, the default is true
printURLs?: boolean | Function;
// Whether to throw an exception when the port is occupied, the default is false
strictPort?: boolean;
// custom Compiler object
compiler?: Compiler | MultiCompiler;
// passing through the build-independent dev server configuration
serverOptions?: Partial<ModernDevServerOptions>;
// Whether to get the port silently, the default is false
getPortSliently?: boolean;
// custom logger
logger?: Logger;
};
type StartServerResult = {
urls: string[];
port: number;
server: Server;
};
function StartDevServer(
options?: StartDevServerOptions,
): Promise<StartServerResult>;
Start Dev Server:
await builder.startDevServer();
After successfully starting Dev Server, you can see the following logs:
info Starting dev server...
> Local: http://localhost:8080
> Network: http://192.168.0.1:8080
startDevServer
returns the following parameters:
urls
: URLs to access dev server.
port
: The actual listening port number.
server
: Server instance object.
const { urls, port, server } = await builder.startDevServer();
console.log(urls); // ['http://localhost:8080', 'http://192.168.0.1:8080']
console.log(port); // 8080
// Close the dev server
await server.close();
Disable Print URLs
Setting printURLs
to false
to disable the default URL output, so you can custom the logs.
await builder.startDevServer({
printURLs: false,
});
You can also directly configure printURLs
as a function to modify URLs, such as adding a subpath to each URL:
await builder.startDevServer({
printURLs: urls => {
return urls.map(({ label, url }) => ({
label,
url: `${url}/path`,
}));
},
});
Strict Port
When a port is occupied, Builder will automatically increment the port number until an available port is found.
Set strictPort
to true
and Builder will throw an exception when the port is occupied.
await builder.startDevServer({
strictPort: true,
});
Custom Compiler
In some cases, you may want to use a custom compiler:
const compiler = webpack({
// ...
});
await builder.startDevServer({
compiler,
});
Get Port Silently
In some cases, the default startup port number is already occupied. In this situation, Builder will automatically increment the port number until it finds an available one. This process will output a prompt log. If you do not want this log, you can set getPortSliently
to true
.
await builder.startDevServer({
getPortSliently: true,
});
Custom Logger
By default, Builder uses @modern-js/utils/logger
to output logs. You can customize the log output object through the logger
parameter.
const customLogger = {
// You need to define the following methods
info(msg: string) {
console.log(msg);
},
error(msg: string) {
console.error(msg);
},
warn(msg: string) {
console.warn(msg);
},
success(msg: string) {
console.log(`✅ msg`);
},
debug(msg: string) {
if (process.env.DEBUG) {
console.log(msg);
}
},
log(msg: string) {
console.log(msg);
};
}
await builder.startDevServer({
logger: customLogger,
});
Then Builder will use the custom logger to output logs.
builder.serve
Start a server to preview the production build locally. This method should be executed after builder.build
.
type StartServerResult = {
urls: string[];
port: number;
server: Server;
};
function server(): Promise<StartServerResult>;
Start the server:
serve
returns the following parameters:
urls
: URLs to access server.
port
: The actual listening port number.
server
: Server instance object.
const { urls, port, server } = await builder.serve();
console.log(urls); // ['http://localhost:8080', 'http://192.168.0.1:8080']
console.log(port); // 8080
// Close the server
await server.close();
builder.createCompiler
Create a Compiler object.
When the target
option of createBuilder
contains only one value, the return value is Compiler
; when target
contains multiple values, the return value is MultiCompiler
.
function CreateCompiler(): Promise<Compiler | MultiCompiler>;
const compiler = await builder.createCompiler();
In most scenarios, you do not need to use this API unless you need to custom the Dev Server or other advanced scenarios.
builder.addPlugins
Register one or more Builder plugins, which can be called multiple times.
This method needs to be called before compiling. If it is called after compiling, it will not affect the compilation result.
type AddPluginsOptions = { before?: string } | { after?: string };
function AddPlugins(
plugins: BuilderPlugins[],
options?: AddPluginsOptions,
): Promise<void>;
builder.addPlugins([builderPluginFoo(), builderPluginBar()]);
// Insert before the bar plugin
builder.addPlugins([builderPluginFoo()], { before: 'bar' });
// Insert after the bar plugin
builder.addPlugins([builderPluginFoo()], { after: 'bar' });
builder.removePlugins
Removes one or more Builder plugins, which can be called multiple times.
This method needs to be called before compiling. If it is called after compiling, it will not affect the compilation result.
function RemovePlugins(pluginNames: string[]): void;
// add plugin
const pluginFoo = builderPluginFoo();
builder.addPlugins(pluginFoo);
// remove plugin
builder.removePlugins([pluginFoo.name]);
builder.isPluginExists
Determines whether a plugin has been registered.
function IsPluginExists(pluginName: string): boolean;
builder.addPlugins([builderPluginFoo()]);
builder.isPluginExists(builderPluginFoo().name); // true
builder.inspectConfig
Inspect the final generated builder config and bundler config.
TIP
The inspectConfig
method does not support simultaneous use with the startDevServer
/ build
method.
When you need to view the complete builder and bundler configurations during the build process, you can use the debug mode or obtain them through hooks such as onBeforeBuild
and onBeforeCreateCompile
.
type InspectConfigOptions = {
// View the config in the specified environment, the default is "development", can be set to "production"
env?: BuilderMode;
// Whether to enable verbose mode, display the complete content of the function in the config, the default is `false`
verbose?: boolean;
// Specify the output path, defaults to the value configured by `output.distPath.root`
outputPath?: string;
// Whether to write the result to disk, the default is `false`
writeToDisk?: boolean;
};
async function InspectConfig(options?: InspectConfigOptions): Promise<{
builderConfig: string;
bundlerConfigs: string[];
origin: {
builderConfig: BuilderConfig;
bundlerConfigs: BundlerConfigs[];
};
}>;
Get the config content in string format:
const { builderConfig, bundlerConfigs } = await builder.inspectConfig();
console.log(builderConfig, bundlerConfigs);
Write the config content to disk:
await builder.inspectConfig({
writeToDisk: true,
});
builder.onBeforeCreateCompiler
onBeforeCreateCompiler
is a callback function that is triggered after the Compiler instance has been created, but before the build process begins. This hook is called when you run builder.startDevServer
, builder.build
, or builder.createCompiler
.
You can access the Compiler instance object through the compiler
parameter:
-
If the current bundler is webpack, you will get the webpack Compiler object.
-
If the current bundler is Rspack, you will get the Rspack Compiler object.
-
Type
function OnBeforeCreateCompiler(
callback: (params: {
bundlerConfigs: WebpackConfig[] | RspackConfig[];
}) => Promise<void> | void,
): void;
builder.onBeforeCreateCompiler(({ bundlerConfigs }) => {
console.log('the bundler config is ', bundlerConfigs);
});
builder.onAfterCreateCompiler
onAfterCreateCompiler
is a callback function that is triggered after the compiler instance has been created, but before the build process. This hook is called when you run builder.startDevServer
, builder.build
, or builder.createCompiler
.
You can access the Compiler instance object through the compiler
parameter:
-
If the current bundler is webpack, you will get the webpack Compiler object.
-
If the current bundler is Rspack, you will get the Rspack Compiler object.
-
Type
function OnAfterCreateCompiler(callback: (params: {
compiler: Compiler | MultiCompiler;
}) => Promise<void> | void;): void;
builder.onAfterCreateCompiler(({ compiler }) => {
console.log('the compiler is ', compiler);
});
builder.onBeforeBuild
onBeforeBuild
is a callback function that is triggered before the production build is executed. You can access the final configuration array of the underlying bundler through the `bundlerConfigs' parameter:
-
If the current bundler is webpack, you will get a webpack configuration array.
-
If the current bundler is Rspack, you will get an Rspack configuration array.
-
The configuration array can contain one or more configurations, depending on the current target
config of Builder.
-
Type
function OnBeforeBuild(
callback: (params: {
bundlerConfigs?: WebpackConfig[] | RspackConfig[];
}) => Promise<void> | void,
): void;
builder.onBeforeBuild(({ bundlerConfigs }) => {
console.log('the bundler config is ', bundlerConfigs);
});
builder.onAfterBuild
onAfterBuild
is a callback function that is triggered after running the production build. You can access the build result information via the `stats' parameter:
-
If the current bundler is webpack, you will get webpack Stats.
-
If the current bundler is Rspack, you will get Rspack Stats.
-
Type
function OnAfterBuild(
callback: (params: { stats?: Stats | MultiStats }) => Promise<void> | void,
): void;
builder.onAfterBuild(({ stats }) => {
console.log(stats?.toJson());
});
builder.onBeforeStartDevServer
Called before starting the development server.
function OnBeforeStartDevServer(callback: () => Promise<void> | void): void;
builder.onBeforeStartDevServer(() => {
console.log('before start!');
});
builder.onAfterStartDevServer
Called after starting the development server, you can get the port number through the port
parameter.
function OnAfterStartDevServer(
callback: (params: { port: number }) => Promise<void> | void,
): void;
builder.onAfterStartDevServer(({ port }) => {
console.log('this port is: ', port);
});
builder.onDevCompileDone
Called after each development environment build, you can use isFirstCompile
to determine whether it is the first build.
function OnDevCompileDone(
callback: (params: { isFirstCompile: boolean }) => Promise<void> | void,
): void;
builder.onDevCompileDone(({ isFirstCompile }) => {
if (isFirstCompile) {
console.log('first compile!');
} else {
console.log('re-compile!');
}
});
builder.onExit
Called when the process is going to exit, this hook can only execute synchronous code.
function OnExit(callback: () => void): void;
builder.onExit(() => {
console.log('exit!');
});
builder.getBuilderConfig
Get the Builder config, this method must be called after the modifyBuilderConfig
hook is executed.
function GetBuilderConfig(): Readonly<BuilderConfig>;
builder.onBeforeBuild(() => {
const config = builder.getBuilderConfig();
console.log(config.html?.title);
});
builder.getNormalizedConfig
Get the normalized Builder config, this method must be called after the modifyBuilderConfig
hook is executed.
Compared with the api.getBuilderConfig
method, the config returned by this method has been normalized, and the type definition of the config will be narrowed. For example, the undefined
type of config.html
will be removed.
It is recommended to use this method to get the Builder config.
function GetNormalizedConfig(): Readonly<NormalizedConfig>;
builder.onBeforeBuild(() => {
const config = api.getNormalizedConfig();
console.log(config.html.title);
});
builder.getHTMLPaths
Get path information for all HTML assets.
This method will return an object, the key is the entry name and the value is the relative path of the HTML file in the dist directory.
function GetHTMLPaths(): Record<string, string>;
builder.onBeforeBuild(() => {
const htmlPaths = api.getHTMLPaths();
console.log(htmlPaths); // { main: 'html/main/index.html' };
});