Plugins expose the full potential of the webpack engine to third-party developers. ———– Webpack

Plugin is more flexible than Loaders because it has access to the WebPack compiler and compilation core. This allows the Plugin to intercept webpack execution with hook functions, or even run a child compiler in tandem with the loader, as MiniCssExtractPlugin does.

Example code: Link

Basic structure of the WebPack Plugin

Taking the htML-webpack-plugin as an example, its use is as follows

plugins: [
    newHtmlWebpackPlugin({ ... }),].Copy the code

It is easy to see that the basic form of the Webpack plugin is a constructor new function(), and in order to get compiler, the plugin needs to expose an interface (the apply function). So, its basic structure is as follows:

  • A named JavaScript function object;
  • In itsprototypeSo, let’s define oneapplyMethods.

There are many ways to achieve this form of JavaScript, this article uses class to achieve, as follows

module.exports = class DemoPlugin {
    apply() {
        console.log('applying')}}Copy the code

Configuring the Development Environment

To be able to run the plugin, we need to create an environment

mkdir webpack-demo-plugin
cd webpack-demo-plugin
npm init
Copy the code

webpack.plugin.js

const path = require("path");

const PATHS = {
  lib: path.join(__dirname, "index.js"),
  build: path.join(__dirname, "build"),};module.exports = {
  entry: {
    lib: PATHS.lib,
  },
  output: {
    path: PATHS.build,
    filename: "[name].js",}};Copy the code

index.js

console.log("hello world")
Copy the code

Also add to package.json

"scripts": {
    "build:plugin": "webpack --config webpack.plugin.js --mode production". }Copy the code

Implement webpack demo

Create a plugins/demo-plugin.js file containing the previous webpack plugin demo and import it into webpack.plugin.js.

webpack.plugin.js

const DemoPlugin = require("./plugins/demo-plugin.js");

module.exports = {
  ...
  / / introduction of the plugin
  plugins: [new DemoPlugin()],
};
Copy the code

Try running NPM run build:plugin and print it on terminal

Applying Hash: 98C8997160AA995a58A4 Version: WebPack 4.12.0 Time: 93ms Built at: 2019-04-29 14:34:31 Asset Size Chunks Chunk Names lib.js 956 bytes 0 [emitted] lib [0] ./index.js 26 bytes {0} [built]Copy the code

It is a surprise to discover that the plug-in is running successfully.

Passing parameters

When applying a plugin, it is sometimes necessary to pass Options to tell the plugin what to do. The constructor of class DemoPlugin is triggered when new DemoPlugin()

plugins/demo-plugin.js

module.exports = class DemoPlugin {
    constructor(options) {
        this.options = options
    }
    apply() {
        console.log('apply'.this.options)
    }
}
Copy the code

You also need to modify webpack.plugin.js to pass the corresponding parameters

module.exports = {
    ...
    plugins: [new DemoPlugin({ name: 'demo'}})],Copy the code

Run NPM run build:plugin to find apply {name: ‘demo’}. Schema-utils can be used to validate Options.

Understand the Compiler and compilation of Webpack

As described earlier in the basic structure of the WebPack Plugin, the Apply function can be used to access the core of webpack. Instead, the apply function takes compiler

plugins/demo-plugin.js

module.exports = class DemoPlugin {
    constructor(options) {
        this.options = options
    }
    apply(compiler) {
        console.log(compiler)
    }
}
Copy the code

Run the NPM Run Build: Plugin again, and you’ll find that all the compiler information is printed on the terminal, with hooks fields being the majority.

Looking at the official documentation, you will see that each hook corresponds to a specific stage. For example, the emit practice is executed before sending resources to the output directory. This allows you to control the compilation process by listening on the hooks.

plugins/demo-plugin.js

module.exports = class DemoPlugin {
    constructor(options) {
        this.options = options
    }
    apply(compiler) {
        compiler.plugin('emit', (compilation, next) => {
            console.log(compilation)

            next()
        })
    }
}
Copy the code

Don’t forget to call next, or WebPack won’t continue to pack.

Running the NPM Run Build: Plugin displays more information than before, because the compiled object contains the entire dependency graph traversed by WebPack. You can access everything related to this, including entries, chunks, modules, assets, etc.

Write files through Compilation

The compilation can be used to write new files or modify files that have already been created. To better write files, we introduce an NPM package

npm install webpack-sources --save-dev
Copy the code

plugins/demo-plugin.js

const { RawSource } = require("webpack-sources");

module.exports = class DemoPlugin {
    constructor(options) {
        this.options = options
    }
    apply(compiler) {
        const { name } = this.options;

        compiler.plugin('emit', (compilation, next) => {
            compilation.assets[name] = new RawSource("demo");

            next()
        })
    }
}
Copy the code

Run the NPM run build:plugin on the terminal

Hash: 98C8997160AA995a58A4 Version: webpack 4.12.0 Time: 95ms Built at: 2019-04-29 16:08:52 Asset Size Chunks Chunk Names lib.js 956 bytes 0 [emitted] lib demo 4 bytes [emitted] [0] ./index.js  26 bytes {0} [built]Copy the code

In the Asset column, we have our own demo file.

For more hooks, see the Official Compilation Reference.

Manages Warnings and Errors

As an experiment, what happens if you insert throw new Error(“Message”) inside apply, the terminal prints Unhandled Rejection Error: Message. Webpack then interrupts execution.

To issue warnings or error messages to the user during compilation without affecting the execution of webpack, use compilation.warnings and compilation.errors.

compilation.warnings.push("warning");
compilation.errors.push("error");
Copy the code

conclusion

When you set out to design a plug-in, be sure to spend time researching existing plug-ins of the same type. Develop plug-ins one by one so that you only validate one at a time. If you have problems, check out the Webpack source code, which will enhance your debug intuition.

Reference:

Webpack.js.org/contribute/…

Survivejs.com/webpack/ext…

Webpack.js.org/api/plugins…