There is no me, there is no me. – chuang tzu

Introduction to the


Plug-ins are the backbone of WebPack. Webpack itself is also built on top of the same plugin system you use in your WebPack configuration! Plug-ins are designed to solve other things that loader cannot implement. To write plug-ins well, you need to know the two core concepts of Compiler, Compilation and tapable in Webpack. The compilation process is already documented in Webpack. Webpack makes it more flexible through the Plugin mechanism to adapt to various application scenarios. A number of events are broadcast during the life cycle of a Webpack run, and the Plugin can listen for these events and change the output when appropriate through the API provided by Webpack.

Implement a Plugin


A WebPack Plugin basically consists of the following steps:

  1. A JavaScript function or class
  2. Define an injection in the function prototypecompilerThe object’sapplyMethods.
  3. applyIn the functioncompilerInserts the specified event hook, retrieved in the hook callbackcompilationobject
  4. usecompilationManipulation to modifywebapackInternal instance data.
  5. Asynchronous plug-in, used after data processingcallbackThe callback

Finally, a simple clean-Webpack-plugin is implemented.

A simple plug-in

class WebpackCleanupPlugin {
  // constructor
  constructor(options) {
    console.log("WebpackCleanupPlugin", options);
  }
  // Apply the function
  apply(compiler) {
    console.log(compiler);
    // Bind the hook event
    compiler.plugin("done", compilation => {
      console.log(compilation); }); }}Copy the code

How to use it is introduced in webpack.config.js and used as follows:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Introduce your own plugin
const WebpackCleanupPlugin = require("./WebpackCleanupPlugin");
module.exports = {
  devtool: "source-map".mode: "production".entry: {
    index: "./src/index.js".chunk1: "./src/chunk1.js"
  },
  output: {
    filename: "[name].[chunkhash].js"
  },
  module: {
    rules: [{test: /\.css$/.use: [MiniCssExtractPlugin.loader, "css-loader"]]}},plugins: [
    // Extract the CSS plug-in
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name].[contenthash].css"
    }),
    // Use your own plugin
    new WebpackCleanupPlugin()
  ]
};
Copy the code

Self-written plug-ins are executed as follows:

  • webpackAfter it is started, it is executed first during the reading of the configurationnew WebpackCleanupPlugin()Initialize a Webpackage CleanupPlugin to get an example.
  • In the initializationcompilerObject, and then calledWebpackCleanupPlugin.apply(compiler)Pass in the plug-in instancecompilerObject.
  • The plug-in instance is being retrievedcompilerAfter the object can be passedcompiler.plugin(Event name, callback function) onWebpackAn event broadcast.
  • And can be accessed throughcompilerObject to operatewebpack.

The Compiler, Compilation,

  • The Compiler object contains all configuration information for the Webpack environment, includingoptions.hook.loaders.pluginsThis information, this object is inWebpackInstantiated at startup, it isGlobally uniqueIt can be simply interpreted asWebpackInstance;CompilerContains the following:

  • The Compilation object contains the current module resources, compile-generated resources, changing files, and so on. whenWebpackRun in development mode whenever a file change is detected, a new oneCompilationWill be created.CompilationObject also provides many event callbacks for plug-ins to extend. throughCompilationYou can also read itCompilerObject.

The Compilation contains something like this:

The difference between Compiler and Compilation is that Compiler represents the entire Webpack lifecycle from startup to shutdown, while Compilation simply represents a new Compilation.

Compiler hooks and compilation hooks

A simple file removal plug-in


If the file is modified each time, a new file will be generated, and the hash of the file will also change, so the changed file and its previous file will be invalid. To remove the previous file, we use the clean-webpack-plugin, which implements a simple file removal. If you don’t know the difference between hash, contenthash, and chunkhash, read this article.

It can be roughly divided into the following steps:

  • To obtainoutputThe path, the exit path, is generally zerodist
  • Bind hook eventcompiler.plugin('done', (stats) => {})
  • Compiles the file, compares it with the original file, and deletes unmatched files (options can also be set to ignore files)

The code implementation is as follows

const recursiveReadSync = require("recursive-readdir-sync");
const minimatch = require("minimatch");
const path = require("path");
const fs = require("fs");
const union = require("lodash.union");

// Match the file
function getFiles(fromPath, exclude = []) {
  const files = recursiveReadSync(fromPath).filter(file= >
    exclude.every(
      excluded= >! minimatch(path.relative(fromPath, file), path.join(excluded), {dot: true})));// console.log(files);
  return files;
}

class WebpackCleanupPlugin {
  constructor(options = {}) {
    // Config file
    this.options = options;
  }
  apply(compiler) {
    // Get the output path
    const outputPath = compiler.options.output.path;
    // Bind the hook event
    compiler.plugin("done", stats => {
      if( compiler.outputFileSystem.constructor.name ! = ="NodeOutputFileSystem"
      ) {
        return;
      }
      // Get the compile completion file name
      const assets = stats.toJson().assets.map(asset= > asset.name);
      console.log(assets);
      // Most combinations are combined and de-duplicated
      const exclude = union(this.options.exclude, assets);
      console.log(exclude);
      // console.log('outputPath', outputPath);
      // Get the unmatched file
      const files = getFiles(outputPath, exclude);
      // const files = [];
      console.log("files", files);
      if (this.options.preview) {
        // console.log('%s file(s) would be deleted:', files.length);
        // Output file
        files.forEach(file= > console.log(" %s", file));
        // console.log();
      } else {
        // Delete unmatched files
        files.forEach(fs.unlinkSync);
      }
      if (!this.options.quiet) {
        // console.log('\nWebpackCleanupPlugin: %s file(s) deleted.', files.length);}}); }}module.exports = WebpackCleanupPlugin;
Copy the code

The above plug-in implements a clean compilation file effect. I won’t do the experiment here. If you are interested, you can copy the code locally and run it to see the results.

conclusion

With a general idea of how to write a simple file-clearing plugin for WebPack, you can do a lot more:

  • Read output resources, code blocks, modules and their dependencies (inemitEvent occurrence)
  • Listening for file changeswatch-run
  • Modifying output Resourcescompilation.assets

The concrete implementation can take a look at Webpack in a nutshell

reference

Dry! 内 容 提 示 webPack plugin (tapable + Webpack process)

Take a look at the real Webpack plug-in