Following up on how to develop the WebPack Loader last time. While the iron is hot, let’s move on to another core component of WebPack: plugin. As with Loader, let’s start with the basic official documentation.

The difference between loader and plugin

  • Loader: a file loader for a type of resource file. Webpack itself cannot package these non-JS files directly, so it needs a converter, namely loader. Loader itself is a single, simple, can not put multiple functions in a loader.
  • Plugin is a bit more advanced than Loaders. You can extend the functionality of WebPack to suit your own needs. In other words, plugin is needed when loader can’t.

How to develop a Plugin

Plug-ins expose all the power of the WebPack engine to third-party developers. Through stepped-build callbacks, developers can add their own behavior to webPack compilation. Developing plug-ins is a bit more advanced than Loaders, because you need to understand some of the underlying components of WebPack to add hook callbacks. Get ready to read some source code.

Developing a plug-in

A webPack plug-in consists of the following aspects:

  • A non-anonymous JS function
  • Define the Apply method on its prototype object
  • Specifies the WebPack hook event that mounts itself
  • Manipulate specific data about what’s going on inside webpack
  • Method completes by invoking the webPack callback
    // A named JavaScript function.
    function MyExampleWebpackPlugin() {
     //
    };
    // Defines `apply` method in it's prototype.
    MyExampleWebpackPlugin.prototype.apply = function(compiler) {
    // Specifies webpack's event hook to attach itself.
    compiler.plugin('webpacksEventHook'.function(compilation /* Manipulates webpack internal instance specific data. */, callback) {
      console.log("This is an example plugin!!!");
      // Invokes webpack provided callback after functionality is complete.
      callback();
    });
    };Copy the code

    Compilers and compilers

The two most important objects in plug-in development are Compiler and compilation. Understanding their responsibilities is the most important first step in extending webPack functionality

The compiler object is the complete configuration environment for WebPack. This object is created as soon as webpack starts executing and is set by all the actionable setup items, such as options, loaders, and plugins. When a plug-in is applied in a WebPack environment, the plug-in receives a reference to the compiler. Use this compiler to access the main WebPack environment.

The compilation object is a separate creation of a compilation resource. When the Webpack development middleware is executed, a new compilation object is created when a change to a file is detected, thus generating resources that can be compiled. A compilation shows information about the current module resource state, compiled resources, changed files, monitored dependencies, and so on. It also provides many key callbacks when plug-ins extend custom behavior

These two components are a required part of the WebPack plug-in (especially the Compilation), so developers who are familiar with these source files will benefit.

  • Compiler Source
  • Compilation Source

The basic structure of the plug-in

A plug-in is an instantiated object with an Apply method in the prototype that is called by WebPack once when the plug-in is installed. The Apply method provides a reference to the currently active Webpack Compiler that allows access to the compiler’s callback. A simple plug-in structure looks like this:

function HelloWorldPlugin(options) {
  // Setup the plugin instance with options...
}

HelloWorldPlugin.prototype.apply = function(compiler) {
  compiler.plugin('done'.function() {
    console.log('Hello World! ');
  });
};

module.exports = HelloWorldPlugin;Copy the code

To install a plugin, simply add an instance of the plugin to your webPack Config array

var HelloWorldPlugin = require('hello-world');

var webpackConfig = {
  // ... config settings here ...
  plugins: [
    new HelloWorldPlugin({options: true}})];Copy the code

Access to compile

By using compiler objects, you might bind callbacks to each new Compilation application. These compilations provide callback functions for many steps in the compilation process.

function HelloCompilationPlugin(options) {}

HelloCompilationPlugin.prototype.apply = function(compiler) {

  // Setup callback for accessing a compilation:
  compiler.plugin("compilation".function(compilation) {

    // Now setup callbacks for accessing compilation steps:
    compilation.plugin("optimize".function() {
      console.log("Assets are being optimized.");
    });
  });
};

module.exports = HelloCompilationPlugin;Copy the code

To learn more about the compiler, which callbacks are available in compilations, and other more important objects, tap the plugin documentation

Asynchronous plug-in

Some compile plug-in steps are asynchronous and provide a callback method that must be called when your plug-in finishes compiling

function HelloAsyncPlugin(options) {}

HelloAsyncPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit".function(compilation, callback) {

    // Do something async...
    setTimeout(function() {
      console.log("Done with async work...");
      callback();
    }, 1000);

  });
};

module.exports = HelloAsyncPlugin;Copy the code

The sample

Once we open the door to the WebPack compiler and each individual compilation, the possibilities for what we can do with the engine are endless. We can reformat existing files, create derived files, and completely forge a new file

Let’s write a simple example plug-in to generate a new file named filelist.md. The contents are as follows: Lists all the build files during the build process. The plugin looks like this:

function FileListPlugin(options) {}

FileListPlugin.prototype.apply = function(compiler) {
  compiler.plugin('emit'.function(compilation, callback) {
    // Create a header string for the generated file:
    var filelist = 'In this build:\n\n';

    // Loop through all compiled assets,
    // adding a new line item for each filename.
    for (var filename in compilation.assets) {
      filelist += (The '-'+ filename +'\n');
    }

    // Insert this list into the webpack build as a new file asset:
    compilation.assets['filelist.md'] = {
      source: function() {
        return filelist;
      },
      size: function() {
        returnfilelist.length; }}; callback(); }); };module.exports = FileListPlugin;Copy the code

Different types of plug-ins

Plug-ins can be divided into different types based on the events they register, and each event hook determines how the plug-in is called when triggered.

Synchronous type

An instance of this type invokes the plug-in as follows

applyPlugins(name: string, args: any...)

applyPluginsBailResult(name: string, args: any...)Copy the code

This means that each plug-in callback will be called in turn with the specific parameter args. This is the simplest format for plug-ins. Many useful events, such as “compile” and “this-compilation”, are expected to be executed synchronously by plug-ins.

Flow type

Waterfall Plugins are called in the following way

applyPluginsWaterfall(name: string, init: any, args: any...)Copy the code

Asynchronous type

An asynchronous plug-in is called when all plug-ins are called asynchronously using the following method

applyPluginsAsync(name: string, args: any... .callback: (err? :Error) - >void)Copy the code

Plug-in control methods are called with all args and flags (Err? : Error) -> void callback. The Handler methods are called in the order in which the registered callbacks are called after all handlers are called. This is a common pattern for “emit”, “run” events.

Asynchronous flow

This plug-in will be used asynchronously in a rundown fashion

applyPluginsAsyncWaterfall(name: string, init: any, callback: (err: Error.result: any) -> void)Copy the code

The plugin’s handler is called with the current value and a flag (Err? : Error) -> void callback. When called, nextValue is the current value of the next handler. The current value of the first handler is init. After all the handlers have been called, the last value will be assigned to the callback. If some handler passes an ERR value, the callback will accept an ERR, and no other handler will be invoked. This plug-in pattern works with events such as “before-resolve” and “after-resolve”.

Asynchronous series

This is similar to asynchronous plug-ins, except that if any plug-ins fail to register, no plug-ins will be called

applyPluginsAsyncSeries(name: string, args: any... .callback: (err: Error.result: any) -> void)Copy the code

conclusion

At this point, HOW to develop a basic Webpack plugin I believe you already know, if not too clear, you can go to the W-Loader to check. Besides, it’s really difficult for me to translate. Here, I hope we can discuss and learn together.