Do you want to learn more about Webpack? Do you want to develop your own WebPack Plugin? I’m just asking. Don’t think about it!

What is a Plugin?

Official document definition: Plug-ins are the backbone of WebPack. Webpack itself is built on top of the same plugin system you use in your WebPack configuration!

Plug-ins are designed to solve other things that the Loader cannot do.

Webpack Plugin is actually a class!!

Create a Plugin

Learn a simple version of the plugin

// myplugin.js class myPlugin {constructor() {console.log('Plugin was created '); } apply(compiler) {} } module.exports = MyPlugin; // webpack.config.js // introduce const MyPlugin = require(' myplugin.js '); module.exports = { plugins: [ new MyPlugin({title: 'MyPlugin'}), ] };Copy the code

Let’s take a look at the Webpack **** official case:

const pluginName = 'ConsoleLogOnBuildWebpackPlugin'; Class ConsoleLogOnBuildWebpackPlugin {the apply (compiler) {/ / is for before you start reading records executive compiler. Hooks. Run. Tap (pluginName, Compilation => {console.log(" Webpack build process started! ") ); }); }}Copy the code

Simple instructions

  • Plugin is really just a class.
  • Class requires an apply method that executes the specific plug-in method.
  • One thing the plug-in method does is register a synchronous log printing method on the Run Hook.
  • The input to the apply method is injected with a Compiler instance, which is the backbone engine of Webpack and represents all the configuration items passed through the CLI and Node apis.
  • The Hook callback method is injected into the Compilation instance, which has access to the current build module and its dependencies.

Is this it? Is this it? Is this it?


Now, the basics

What is a Hook?

Webpack triggers a series of processes during compilation. In this process, Webpack exposes some key process nodes for developers to use. These are hooks, similar to React/Vue lifecycle hooks.

Plugins expose methods on these hooks for developers to do some extra work, so when writing plugins, we need to know which Hook we should work on first.

Webpack provides a total of ten Hooks, and every specific Hook in your code is one of these ten.

// source from: lib/index.js "use strict"; exports.__esModule = true; Exports. SyncHook = require("./SyncHook"); // Block downward execution of exports.SyncBailHook = require("./SyncBailHook"); // Block downward execution of exports.SyncBailHook = require("./SyncBailHook"); / / simultaneous execution of hook, support will return values through to the next hook the exports. SyncWaterfallHook = the require (". / SyncWaterfallHook "); // exports.SyncLoopHook = require("./SyncLoopHook"); // exports. / / asynchronous parallel hooks exports. AsyncParallelHook = the require (". / AsyncParallelHook "); / / asynchronous parallel hooks, return is not empty, stop execution down, direct execution callback exports. AsyncParallelBailHook = the require (". / AsyncParallelBailHook "); // hook exports.AsyncSeriesHook = require("./AsyncSeriesHook"); / / asynchronous serial port of hook, return is not empty, stop execution down, direct execution callback exports. AsyncSeriesBailHook = the require (". / AsyncSeriesBailHook "); / / support asynchronous serial port && parallel hooks, return is not empty, repeat exports. AsyncSeriesLoopHook = the require (". / AsyncSeriesLoopHook "); / / asynchronous serial port of hook, dependence on the next step returns the value of exports. AsyncSeriesWaterfallHook = the require (". / AsyncSeriesWaterfallHook "); HookMap = require("./HookMap"); exports.MultiHook = require("./MultiHook");Copy the code

The type of Hook can be through the official API queries, address portal: www.webpackjs.com/api/compile…

The core tool library Tapable

What is Tapable? A Webpack is a stream of events that are made up of plug-ins, and keeping them running in order is what Tapable does, using a publish-subscribe architectural pattern. Tapable has a number of hook methods for collecting registered plugins. Tapable is simply a library that WebPack uses to create hooks.

Tapable is the core Webpack tool library that provides abstract class definitions for all hooks. Many Webpack objects are inherited from Tapable. Such as tap, tapAsync and tapPrimise.

// In section 2, "Create a Plugin," the 10 Hooks are inherited from these two classes. tapable.d.ts declare class Hook<T, R, AdditionalOptions = UnsetAdditionalOptions> { tap(options: string | Tap & IfSet<AdditionalOptions>, fn: (... args: AsArray<T>) => R): void; } declare class AsyncHook<T, R, AdditionalOptions = UnsetAdditionalOptions> extends Hook<T, R, AdditionalOptions> { tapAsync( options: string | Tap & IfSet<AdditionalOptions>, fn: (... args: Append<AsArray<T>, InnerCallback<Error, R>>) => void ): void; tapPromise( options: string | Tap & IfSet<AdditionalOptions>, fn: (... args: AsArray<T>) => Promise<R> ): void; }Copy the code

What is a compiler?

Compiler contains all the configuration information for the WebPack environment. This object is created once when webpack is started and all operational Settings, including options, Loader and plugin, are configured. When a plug-in is applied in a WebPack environment, the plug-in collects a reference to this Compiler object. You can use it to access webPack’s main environment.

What is a compilation?

The Compilation object contains the current module resources, compiled and generated resources, and changed files. When running the WebPack development environment middleware and no file change is detected, the resource is created.

The Compilation object also provides a number of time-critical callbacks that plug-ins can choose to use when doing custom processing.

Compiler and compilation?

The Compiler object contains all configuration information for the Webpack environment, including options, loaders, and plugins. This object is instantiated at Webpack startup. It is globally unique and can be easily understood as a Webpack instance. The Compilation object contains the current module resources, compiled and generated resources, and changed files. When Webpack is running in development mode, a new Compilation is created each time a file change is detected. The Compilation object also provides a number of event callbacks for plug-in extensions. Compiler objects can also be read through Compilation. -- From WebpackCopy the code
  1. The cycle length varies with the generation time. Compiler exists throughout the webPack life cycle from start to close, and compilation simply represents a new compilation process.
  2. Compiler and Compilation expose different hooks.

Compiler is a common hook

Hook type call
run AsyncSeriesHook Before you start reading records
compile SyncHook After a new compilation is created
emit AsyncSeriesHook Before generating resources into the Output directory
done SyncHook Compilation is complete
initialize SyncHook Called when the compiler object is initialized (useful in html-webpack-plugin)

Compilation commonly used hooks

Hook type call
buildModule SyncHook Triggers before module build begins.
finishModules SyncHook All modules are built.
optimize SyncHook Triggered at the beginning of the optimization phase.

Other did not do too much introduction, attach a website link webpack.docschina.org/api/compile…


Complete a complete Webpack Plugin

The name of the Webpack plugin is xxx-webpack-plugin, and the plugin demo begins.

Copyright-webpack-plugin

This is a simple demo that uses plugin to generate a markdown file that outputs ‘written by zhulm’

// plugin class
class CopyrightWebpackPlugin {
  constructor () {}
  apply(compiler) {
    // console.log('compiler: ', compiler);
    compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', 
      (compilation,cb) => {
        // console.log('compilation: ', compilation);
        compilation.assets['copyright.md'] = {
          source: function() {
            return 'written by zhulm';
          },
          size: function() {
            return 15;
          },
        }
        cb()
      }
    )
  }
}
module.exports = CopyrightWebpackPlugin;
Copy the code

Code explanation:

  1. Use the emit method of the single compiler hook to create a copyright. Md file and write the text.
  2. The tapAsync method calls the hook with two arguments. The first argument is the name of the plugin itself, and the second argument is a function.
  1. Source is the source file, and size is the size of the generated file. Returning 15 means that the generated file size is 15 bytes.
  2. Assets: {[pathName: string]: Source} – A normal object where key is the pathname of the asset and value is the data of the asset

See my github address: github.com/dakoujia/we…

OutputCurrentBuildInfoPlugin

Git commit: This plugin is a plugin that gets output information, git commit information and time

new OutputCurrentBuildInfoPlugin({
      outputName: 'build-log.json',
      dateFormatType: 'YYYY-MM-DD HH:mm:ss',
      buildType: 'local'
    }),
Copy the code

Generated by the build – the json

// local {"build_time":"2021-07-04 20:28:20","build_type":"local","git":{"currentBranch":"","build_user":{"name":"zhulm","email":"[email protected] "}}}Copy the code
// git {"build_time":"2021-07-04 21:26:59","build_type":"git","git":{"last_commit":{"hash":"f94253ba4af5727f1b9bd48f9b0b225723d597a4","date":"2021-07-04T 21:19:44+08:00","message":"docs(read me): README.md","refs":"HEAD -> main, origin/main, Origin /HEAD","body":" author_name":"zhulm","author_email":"[email protected]"},"currentBranch":"main" ,"build_user":{"name":"zhulm","email":"[email protected]"}}}Copy the code

See my github address: github.com/dakoujia/we…

Problems encountered

1. An error occurs during construction

Webpack version problem, webpack5.0 or above will have this problem, the version reduced to 4.16.5 can be solved;

reference

Webpack Plugin: juejin.cn/post/684490…

Official website of the plugin: webpack.docschina.org/plugins/