Plugins
Plugins are the backbone of webpack. Webpack itself is built on the same plugin system that you use in your webpack configuration!
They also serve the purpose of doing anything else that a loader cannot do. Webpack provides many such plugins out of the box.
Anatomy
A webpack plugin is a JavaScript object that has an apply method. This apply method is called by the webpack compiler, giving access to the entire compilation lifecycle.
ConsoleLogOnBuildWebpackPlugin.js
const pluginName = "ConsoleLogOnBuildWebpackPlugin";
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compiler) => {
console.log("The webpack build process is starting!");
});
}
}
export default ConsoleLogOnBuildWebpackPlugin;It is recommended that the first parameter of the tap method of the compiler hook should be a camelized version of the plugin name. It is advisable to use a constant for this so it can be reused in all hooks.
Usage
Since plugins can take arguments/options, you must pass a new instance to the plugins property in your webpack configuration.
Depending on how you are using webpack, there are multiple ways to use plugins.
Configuration
webpack.config.js
import path from "node:path";
import { fileURLToPath } from "node:url";
import webpack from "webpack"; // to access built-in plugins
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
entry: "./src/index.html",
experiments: {
html: true,
},
output: {
filename: "my-first-webpack.bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
},
],
},
plugins: [new webpack.ProgressPlugin()],
};The ProgressPlugin is used to customize how progress should be reported during compilation. src/index.html is the entry, so webpack emits it as the page with the <script src> it references rewritten to the built chunk — no plugin is needed for that, see Native HTML.
Node API
When using the Node API, you can also pass plugins via the plugins property in the configuration.
some-node-script.js
import webpack from "webpack"; // to access webpack runtime
import configuration from "./webpack.config.js";
const compiler = webpack(configuration);
new webpack.ProgressPlugin().apply(compiler);
compiler.run((err, stats) => {
// ...
});Writing your own
The Writing a Plugin guide takes the object above and builds it out into a real plugin — options, async hooks, file dependencies for watch mode, types and tests.
Two things decide whether a plugin behaves well, and both are about which hook it taps.
Where the hooks live
Hooks belong to the object that owns them, and the two reference pages list them in the order they run:
- Compiler hooks — once per build, around the whole run:
run,watchRun,compile,make,emit,done. - Compilation hooks — inside a single build, over modules, chunks and assets.
A compiler outlives the builds it runs: in watch mode every rebuild is a new Compilation on the same Compiler. State that must survive a rebuild belongs on the compiler; state about one build belongs on the compilation.
Creating or changing assets
Do it in processAssets, with the stage that matches the work — PROCESS_ASSETS_STAGE_ADDITIONAL to emit a new file, PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE to minify, and so on.



