website/docs/en/api/plugin-api/compiler-hooks.mdx
import Mermaid from '@components/Mermaid'; import CompilerType from '../../types/compiler.mdx'; import CompilationType from '../../types/compilation.mdx'; import StatsType from '../../types/stats.mdx'; import { Collapse, CollapsePanel } from '@components/Collapse'; import Columns from '@components/Columns'; import { NoSSR } from '@rspress/core/runtime';
Compiler hooks allow Rspack plugins to intervene at specific stages of the build process. These hooks represent various lifecycle stages from initialization to asset output.
This document lists the available compiler hooks in Rspack, their trigger timing, parameters, and usage examples.
:::tip See Compiler for more information about the Compiler object. :::
<Mermaid title="rspack()" style={{width: '20rem'}}> {` flowchart TD CallRspack("rspack()") --> CreateCompiler("new Compiler()") CreateCompiler --> ApplyNodeEnvPlugin(Apply NodeEnvironmentPlugin) ApplyNodeEnvPlugin --> ApplyDefaultOptions(Apply default options) ApplyDefaultOptions --> ApplyCustomPlugins(Apply custom plugins) ApplyCustomPlugins --> HookEnvironment(<a href="#environment">hooks.environment</a>) HookEnvironment --> HookAfterEnvironment(<a href="#afterenvironment">hooks.afterEnvironment</a>) HookAfterEnvironment --> ApplyRspackPlugins(Apply internal plugins) ApplyRspackPlugins <--> HookEntryOptions(<a href="#entryoption">hooks.entryOption</a>) ApplyRspackPlugins --> HookAfterPlugins(<a href="#afterplugins">hooks.afterPlugins</a>) HookAfterPlugins --> ResolveOptions(Generate resolve options) ResolveOptions --> HookAfterResolvers(<a href="#afterresolvers">hooks.afterResolvers</a>) HookAfterResolvers --> HookInitialize(<a href="#initialize">hooks.initialize</a>) HookInitialize --> compiler("return compiler")
class CallRspack flow-start class compiler flow-end class CreateCompiler,ApplyNodeEnvPlugin,ApplyDefaultOptions,ApplyCustomPlugins,ApplyRspackPlugins,ResolveOptions flow-process class HookEnvironment,HookAfterEnvironment,HookEntryOptions,HookAfterPlugins,HookAfterResolvers,HookInitialize flow-hook `}
</Mermaid> <Mermaid title="compiler.compile()">{` flowchart TD Compile("compiler.compile(callback)") --> CompilationParams("Create module factories") CompilationParams --> HookNormalModuleFactory(hooks.normalModuleFactory) CompilationParams --> HookContextModuleFactory(hooks.contextModuleFactory) CompilationParams --> HookBeforeCompile(<a href="#beforecompile">hooks.beforeCompile</a>) HookBeforeCompile --> HookCompile(<a href="#compile">hooks.compile</a>) HookCompile --> Compilation("new Compilation()") Compilation --> HookThisCompilation(<a href="#thiscompilation">hooks.thisCompilation</a>) HookThisCompilation --> HookCompilation(<a href="#compilation">hooks.compilation</a>) HookCompilation --> HookMake(<a href="#make">hooks.make</a>) HookMake --> CreateModuleGraph(Create module graph) CreateModuleGraph <--> RunLoaders(Run loaders on modules) CreateModuleGraph --> HookFinishMake(<a href="#finishmake">hooks.finishMake</a>) HookFinishMake --> CompilationFinish("compilation.finish()") CompilationFinish --> CompilationSeal("compilation.seal()") CompilationSeal --> HookAfterCompile(<a href="#aftercompile">hooks.afterCompile</a>) HookAfterCompile --> Callback("callback()")
class Compile flow-start class Callback,CloseCallback flow-end class CompilationParams,Compilation,CreateModuleGraph,RunLoaders,CompilationFinish,CompilationSeal flow-process class HookBeforeCompile,HookCompile,HookThisCompilation,HookCompilation,HookMake,HookFinishMake,HookAfterCompile flow-hook class HookNormalModuleFactory,HookContextModuleFactory flow-hook-non-support `}
</Mermaid> </div> <Mermaid title="compiler.watch/run/close()">{` flowchart TD WatchCompiler("compiler.watch(options, callback)") --> CreateWatching("new Watching()") RunCompiler("compiler.run(callback)") --> HookBeforeRun(<a href="#beforerun">hooks.beforeRun</a>) HookBeforeRun --> HookRun(<a href="#run">hooks.run</a>) HookRun --> HookReadRecords(hooks.readRecords) CreateWatching --> HookReadRecords HookReadRecords --> Compile("compiler.compile()") HookWatchRun --> Compile HookReadRecords --> HookWatchRun(<a href="#watchrun">hooks.watchRun</a>) Compile --> HookShouldEmit{<a href="#shouldemit">hooks.shouldEmit</a>} HookShouldEmit --> |true| HookEmit(<a href="#emit">hooks.emit</a>) HookShouldEmit --> |false| HookDone(<a href="#done">hooks.done</a>) HookEmit --> EmitAssets(Emit asset files) EmitAssets <--> HookAssetEmitted(hooks.assetEmitted) EmitAssets --> HookAfterEmit(<a href="#afteremit">hooks.afterEmit</a>) HookAfterEmit --> HookNeedAdditionalPass{hooks.needAdditionalPass} HookNeedAdditionalPass --> |true| HookAdditionalDone(hooks.done) HookAdditionalDone --> HookAdditionPass(hooks.additionalPass) HookAdditionPass --> Compile HookEmitRecords --> HookDone HookDone --> HookFailed(<a href="#failed">hooks.failed</a>) HookFailed --> Callback("callback(err, stats)") Callback --> WatchingWatch("watching.watch()") WatchingWatch --> HookAfterDone(<a href="#afterdone">hooks.afterDone</a>) WatchingWatch --> CollectFileChanges("Collect file changes") CollectFileChanges --> HookReadRecords Callback --> HookAfterDone
HookAfterDone -.-> CloseCompile("compiler.close(callback)") CloseCompile --> WatchingClose("watching.close()") WatchingClose --> HookWatchClose(<a href="#watchclose">hooks.watchClose</a>) HookWatchClose --> CloseCallback("callback()") CloseCallback --> HookShutdown(<a href="#shutdown">hooks.shutdown</a>)
class RunCompiler,WatchCompiler flow-start class Callback flow-end class Compile,EmitAssets,CollectFileChanges,CreateWatching,WatchingWatch flow-process class HookBeforeRun,HookRun,HookShouldEmit,HookEmit,HookAfterEmit,HookDone,HookFailed,HookAfterDone,HookWatchRun flow-hook class HookReadRecords,HookAssetEmitted,HookNeedAdditionalPass,HookAdditionPass,HookAdditionalDone,HookEmitRecords flow-hook-non-support
class CloseCompile flow-start class CloseCallback flow-end class WatchingClose flow-process class HookWatchClose,HookShutdown flow-hook `}
</Mermaid> </Columns> </NoSSR>environmentCalled while preparing the compiler environment, right after initializing the plugins in the configuration file.
SyncHook<[]>afterEnvironmentCalled right after the environment hook, when the compiler environment setup is complete.
SyncHook<[]>entryOptionCalled after the entry configuration from Rspack options has been processed.
SyncBailHook<[string, EntryNormalized]>afterPluginsCalled after setting up initial set of internal plugins.
SyncHook<[Compiler]>Compiler: current compiler instanceafterResolversTriggered after resolver setup is complete.
SyncHook<[Compiler]>Compiler: current compiler instanceinitializeCalled when a compiler object is initialized.
SyncHook<[]>beforeRunAdds a hook right before running the compiler.
:::note
This hook is only triggered when calling compiler.run() (which is used by the rspack build command), and will not be executed in watch mode. You can use the watchRun hook in watch mode.
:::
AsyncSeriesHook<[Compiler]>Compiler: current compiler instanceclass ExamplePlugin {
apply(compiler) {
compiler.hooks.beforeRun.tap('ExamplePlugin', (compiler) => {
console.log('Build is about to start...');
});
}
}
class ExamplePlugin {
apply(compiler) {
compiler.hooks.beforeRun.tapPromise(
'ExamplePlugin',
(compiler) => {
console.log('Build is about to start...');
await someAsyncOperation();
},
);
}
}
runCalled at the beginning of a build execution.
:::note
This hook is only triggered when calling compiler.run() (which is used by the rspack build command), and will not be executed in watch mode. You can use the watchRun hook in watch mode.
:::
AsyncSeriesHook<[Compiler]>Compiler: current compiler instanceclass ExamplePlugin {
apply(compiler) {
compiler.hooks.beforeRun.tap('ExamplePlugin', (compiler) => {
console.log('Build start...');
});
}
}
class ExamplePlugin {
apply(compiler) {
compiler.hooks.beforeRun.tapPromise(
'ExamplePlugin',
(compiler) => {
console.log('Build start...');
await someAsyncOperation();
},
);
}
}
watchRunExecutes a plugin during watch mode after a new compilation is triggered but before the compilation is actually started.
You can use compiler.modifiedFiles and compiler.removedFiles to get the changed file paths and removed file paths.
:::note
This hook is only triggered when calling compiler.watch(), and will not be called in non-watch mode. You can use the run or beforeRun hook in non-watch mode.
:::
AsyncSeriesHook<[Compiler]>Compiler: current compiler instanceclass ExamplePlugin {
apply(compiler) {
compiler.hooks.watchRun.tap('ExamplePlugin', (compiler) => {
const { modifiedFiles, removedFiles } = compiler;
if (modifiedFiles) {
console.log('Changed files:', Array.from(modifiedFiles));
}
if (removedFiles) {
console.log('Removed files:', Array.from(removedFiles));
}
});
}
}
class ExamplePlugin {
apply(compiler) {
compiler.hooks.watchRun.tapPromise('ExamplePlugin', compiler => {
await someAsyncOperation();
});
}
}
beforeCompileExecutes a plugin after compilation parameters are created.
AsyncSeriesHook<[]>compileCalled right after beforeCompile, before a new compilation object is created.
SyncHook<[]>thisCompilationCalled while initializing the compilation, can be used to get the current compilation object.
You can use the compilation parameter to access the properties of the compilation object, or register compilation hooks.
SyncHook<[Compilation]>compilation: created compilation objectclass ExamplePlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap('ExamplePlugin', (compilation) => {
console.log('compilation created:', compilation);
compilation.hooks.make.tap('ExamplePlugin', (compilation) => {
console.log("compilation's make hook called:", compilation);
});
});
}
}
compilationCalled after the compilation object is created, can be used to get the current compilation object.
You can use the compilation parameter to access the properties of the compilation object, or register compilation hooks.
compilation hook is called after the thisCompilation hook, and thisCompilation hook is not copied to child compiler, while compilation hook is copied to child compiler.
SyncHook<[Compilation]>compilation: created compilation objectclass ExamplePlugin {
apply(compiler) {
compiler.hooks.compilation.tap('ExamplePlugin', (compilation) => {
console.log('compilation created:', compilation);
compilation.hooks.make.tap('ExamplePlugin', (compilation) => {
console.log("compilation's make hook called:", compilation);
});
});
}
}
makeCalled before the make phase.
In the make phase, Rspack will build the module graph starting from the entry, and use the loader to handle each module.
AsyncParallelHook<[Compilation]>Compilation: current compilation objectfinishMakeCalled after finishing the make phase.
In the make phase, Rspack builds the module graph starting from the entry and uses loaders to handle each module. This hook is called when that process completes.
AsyncSeriesHook<[Compilation]>Compilation: current compilation objectafterCompileCalled after the make phase and before the seal phase.
In the seal phase, Rspack will create chunk graph from the module graph and then generate the assets.
AsyncSeriesHook<[Compilation]>Compilation: current compilation objectshouldEmitCalled before emitting assets. Should return a boolean telling whether to emit.
SyncBailHook<[Compilation], boolean>Compilation: current compilation objectcompiler.hooks.shouldEmit.tap('MyPlugin', (compilation) => {
// return true to emit the output, otherwise false
return true;
});
emitCalled right before emitting assets to output dir.
AsyncSeriesHook<[Compilation]>Compilation: current compilation objectafterEmitCalled after emitting assets to output directory.
AsyncSeriesHook<[Compilation]>Compilation: current compilation objectdoneCalled when the compilation has completed.
AsyncSeriesHook<Stats>Stats: generated stats objectafterDoneCalled after done hook.
SyncHook<Stats>Stats: generated stats objectfailedCalled if the compilation fails.
SyncHook<[Error]>invalidExecuted when a watching compilation has been invalidated. This hook is not copied to child compilers.
SyncHook<[string | null, number]>fileName: the file path of the invalid filechangeTime: the change time of the invalid fileWhen triggering a re-compilation, this hook can be used to get the changed file path and change time, for example:
compiler.hooks.invalid.tap('MyPlugin', (fileName, changeTime) => {
console.log(`Changed file: ${fileName}, change time: ${changeTime}`);
});
watchCloseCalled when a watching compilation has stopped.
SyncHook<[]>shutdownCalled when the compiler is closing.
AsyncSeriesHook<[]>Called when infrastructure logging is triggered, allowing plugins to intercept, modify, or handle log messages.
This hook provides a way to customize Rspack's infrastructure logs - you can filter specific log types, add custom formatting, or completely override the default logging behavior.
If the hook returns true, the default infrastructure logging will be prevented. If it returns undefined, the default logging will proceed.
SyncBailHook<[string, string, any[]], true | void>name: The name of the loggertype: The log type (e.g., 'log', 'warn', 'error', ...)args: An array of arguments passed to the logging methodclass ExamplePlugin {
apply(compiler) {
compiler.hooks.infrastructureLog.tap('MyPlugin', (name, type, args) => {
// Custom logging logic
if (type === 'error') {
console.error(`[${name}] ERROR:`, ...args);
return true; // Prevent default logging
}
// Let other log types use default behavior
return undefined;
});
}
}
See infrastructureLogging to learn more about infrastructure logging.