Frontend Development 18 min read

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.

政采云技术
政采云技术
政采云技术
Hands‑On Introduction to Writing a Webpack Plugin

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.

frontendJavaScriptpluginBuild ToolWebpackHooksTapable
政采云技术
Written by

政采云技术

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.