Documentation Index
Fetch the complete documentation index at: https://docs.webpack.js.org/llms.txt
Use this file to discover all available pages before exploring further.
Webpack plugins are JavaScript objects with an apply method. This method is called by the webpack compiler, giving plugins access to the entire compilation lifecycle.
Basic Plugin Structure
A minimal webpack plugin looks like this:
class MyPlugin {
apply(compiler) {
// Plugin logic here
}
}
module.exports = MyPlugin;
Using Compiler Hooks
The compiler exposes hooks that allow you to tap into different stages of the build process:
class MyPlugin {
apply(compiler) {
compiler.hooks.compile.tap('MyPlugin', (params) => {
console.log('The compiler is starting to compile...');
});
compiler.hooks.done.tap('MyPlugin', (stats) => {
console.log('The compilation has finished!');
});
}
}
Available Hooks
Common compiler hooks include:
entryOption - Called after entry configuration is processed
beforeRun - Called before running the compiler
run - Called when the compiler starts running
compile - Called before a new compilation is created
compilation - Called when a compilation is created
emit - Called before assets are emitted to output directory
done - Called when compilation finishes
Accessing Compilation
For more detailed control, tap into the compilation hook:
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
compilation.hooks.optimize.tap('MyPlugin', () => {
console.log('Assets are being optimized.');
});
});
}
}
Async Hooks
Some hooks support asynchronous operations:
class MyPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
setTimeout(() => {
console.log('Async operation complete');
callback();
}, 1000);
});
}
}
Using Promises
You can also use promises with tapPromise:
class MyPlugin {
apply(compiler) {
compiler.hooks.emit.tapPromise('MyPlugin', async (compilation) => {
await someAsyncOperation();
console.log('Promise resolved');
});
}
}
Example: Adding Custom Assets
const { RawSource } = require('webpack-sources');
class CreateFilePlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap('CreateFilePlugin', (compilation) => {
compilation.hooks.processAssets.tap(
{
name: 'CreateFilePlugin',
stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
},
() => {
compilation.emitAsset(
'custom-file.txt',
new RawSource('This is custom content')
);
}
);
});
}
}
Plugin Options
Plugins typically accept options in their constructor:
class MyPlugin {
constructor(options = {}) {
this.options = options;
}
apply(compiler) {
const { message = 'Hello!' } = this.options;
compiler.hooks.done.tap('MyPlugin', () => {
console.log(message);
});
}
}
// Usage
new MyPlugin({ message: 'Build complete!' });
Best Practices
Always give your plugin a clear, descriptive name when using .tap() - this helps with debugging and understanding the build process.
Be careful with asynchronous operations. Always call the callback or resolve the promise to avoid hanging the build process.