Hands‑On Introduction to Writing a Webpack Plugin
This article provides a step‑by‑step guide to understanding Webpack fundamentals, the role of plugins, hook mechanisms, and a complete example of creating a custom plugin that merges route files into a unified router configuration for a large React project.
About Webpack
Webpack is a static module bundler for modern JavaScript applications. It parses code, builds a dependency graph, and emits one or more bundles.
Core concepts include Entry, Output, Loader, Plugin, Mode, and Browser Compatibility.
Purpose of Plugins
Plugins can perform tasks that loaders cannot, such as generating a unified router file in a large React project. The article shows an internal case where a plugin reads all index.js files under route folders and merges them into a single router configuration.
Before the plugin, the project structure looks like:
├── package.json
├── README.md
├── zoo.config.js
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .stylelintrc
├── build (Webpack 配置目录)
│ └── webpack.dev.conf.js
├── src
│ ├── index.hbs
│ ├── main.js (入口文件)
│ ├── common (通用模块)
│ ├── components (公共组件)
│ ├── layouts (项目布局)
│ ├── utils (公共类)
│ ├── routes
│ │ ├── Hello
│ │ │ ├── config
│ │ │ ├── models
│ │ │ ├── services
│ │ │ ├── views
│ │ │ └── index.js (router定义的路由信息)After the plugin, the structure changes to:
├── package.json
├── README.md
├── zoo.config.js
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .stylelintrc
├── build (Webpack 配置目录)
│ └── webpack.dev.conf.js
├── src
│ ├── index.hbs
│ ├── main.js (入口文件)
│ ├── router-config.js (合成后的router文件)
│ ├── common (通用模块)
│ ├── components (公共组件)
│ ├── layouts (项目布局)
│ ├── utils (公共类)
│ ├── routes …Creating a Plugin
Hook
Webpack exposes lifecycle hooks (similar to React lifecycle) that plugins can tap into. Plugins register methods on these hooks to execute custom logic.
How to Create a Plugin
Official example:
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
// run before reading records
compiler.hooks.run.tap(pluginName, compilation => {
console.log("webpack 构建过程开始!");
});
}
}Key points:
A plugin is a class.
The class must implement an apply method.
The apply method receives a compiler instance and registers callbacks on hooks (e.g., compiler.hooks.run.tap ).
The compiler and compilation objects expose many hooks via the hooks property, supporting tap , tapAsync , and tapPromise .
Webpack provides ten built‑in hook types (SyncHook, AsyncSeriesHook, etc.). An example of using the run hook with tapAsync is shown:
compiler.plugin('before-compile', (compilation, callback) => {
// custom logic
callback();
});Webpack & Tapable
Webpack Execution Process
Merge the configuration file and CLI arguments into options .
Create a compiler instance with those options and instantiate its hooks.
Call compiler.run , which automatically triggers beforeRun , run , beforeCompile , compile , and other key hooks.
Create a compilation object; it manages all modules and triggers the make hook.
Execute compilation.addEntry() to resolve entry files, recursively parse dependencies, and trigger hooks such as beforeResolve , resolver , afterResolve , and module .
Add and build modules via compilation.addModule() and compilation.buildModule() , then call seal to generate chunks and output files.
Tapable
Tapable is the core utility library that defines hook abstractions. Both compiler and compilation inherit from Tapable, exposing tap , tapAsync , and tapPromise methods for plugin developers.
Plugin in a Real Project
The plugin reads each folder under src/routes , extracts router information, merges paths, models, and child routes, and writes a router-config.js file. The full implementation code is provided in the article.
Before merging, the router file is an array of route objects:
module.exports = [
{ url: '/category/protocol', view: 'protocol' },
{ url: '/category/sync', models: ['sync'], view: 'sync' },
// ...more routes
];After merging, it becomes an object keyed by URL with consolidated path and models arrays:
module.exports = {
"/category/protocol": { "path": "Category/views/protocol" },
"/category/sync": {
"path": "Category/views/sync",
"models": ["routes/Category/models/sync.js"]
},
// ...more routes
};Conclusion
Readers should now have a basic understanding of Webpack plugins, the hook system, and be able to write a custom plugin to solve project‑specific problems.
政采云技术
ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.