The plugin plugin mechanism in Webpack

Have you ever encountered these problems:

  • The files packaged by webpack are not compressed
  • Static files should be manually copied to the output directory
  • A lot of redundant code for environment judgment is written in the code

The previous article "webpack core features" loader mentioned  loader the mechanism of webpack. This article mainly talks about another core feature: plug-in ( plugin).

The plug-in mechanism is to complete other automation tasks in the project except resource module packaging, and solve the above problems.

plugin It is used to extend the functionality of webpack by injecting hooks into the build process, which brings great flexibility to webpack.

What is the difference between plugin and loader?

loader It is a converter, which compiles and converts one type of file into another file, and operates the file. For example: converting  .less a file to  .css a file.

plugin It is an expander, which is aimed at  loader the whole process of packaging after the end. It does not directly manipulate files, but works based on the event mechanism. Corresponding events will be broadcast at specific times in the webpack build process, and plug-ins can listen to the occurrence of these events and do corresponding things at specific times. Including: packaging optimization, resource management, injection of environment variables.

How should the plugin be configured?

For example  HtmlWebpackPlugin an HTML file can be generated for us that includes  script all modules in the body using tags. See how to configure:

const HtmlWebpackPlugin = require('html-webpack-plugin');

const webpackConfig = {
  ...
  plugins: [new HtmlWebpackPlugin()]
};

Reminder: loader Configured in module.rules, as the parsing rules of the module, the type is an array. Each item is an object, which contains attributes such as test (type file), loader, and options (parameters). plugin It is configured separately, the type is an array, each item is an  plugin instance, and the parameters are passed in through the constructor.

What common plugins are there?

The list of plug-ins compiled below comes from the webpack Chinese official website. If you see something you are not familiar with, you  plugin can click the name to jump, take a look, and learn about the specific gameplay.

name describe
AggressiveSplittingPlugin Divide the original chunk into smaller chunks
BabelMinifyWebpackPlugin Minify with babel-minify
BannerPlugin Add a banner at the top of each generated chunk
CommonsChunkPlugin Extract common modules shared between chunks
CompressionWebpackPlugin A pre-prepared compressed version of resources, using Content-Encoding to provide access services
ContextReplacementPlugin Override the inference context of require expressions
CopyWebpackPlugin Copy individual files or entire directories to the build directory
DefinePlugin Global constants that allow configuration at compile time
DllPlugin In order to greatly reduce the build time, dll subpackage
EnvironmentPlugin Shorthand for the process.env key in DefinePlugin.
ExtractTextWebpackPlugin Extract text (CSS) from bundle to separate file
HotModuleReplacementPlugin Enable Hot Module Replacement (HMR)
HtmlWebpackPlugin Simple creation of HTML files for server access
I18nWebpackPlugin Add internationalization support to bundle
IgnorePlugin Exclude certain modules from the bundle
LimitChunkCountPlugin Set min/max limits for chunks to fine tune and control chunks
LoaderOptionsPlugin For migrating from webpack 1 to webpack 2
MinChunkSizePlugin Make sure the chunk size exceeds the specified limit
NoEmitOnErrorsPlugin During the output stage, when a compilation error is encountered, skip
NormalModuleReplacementPlugin Replace resources that match a regular expression
NpmInstallWebpackPlugin Automatically install missing dependencies during development
ProvidePlugin No need to use modules via import/require
SourceMapDevToolPlugin Fine-grained control over source maps
EvalSourceMapDevToolPlugin Fine-grained control over eval source maps
UglifyjsWebpackPlugin Can control the version of UglifyJS in the project
ZopfliWebpackPlugin A pre-compressed version of resources via node-zopfli

How to write a plugin?

Before talking about how to write plug-ins, let me briefly introduce a few fun things: tapable, compiler and  compilation.

tapable

tapable It is a similar  nodejs library  EventEmitter , mainly to control the publication and subscription of hook functions. Of course, the mechanism tapable provided  is relatively comprehensive, which is divided into two categories: synchronous  and  asynchronous (asynchronous parallel and asynchronous serial are distinguished in asynchronous), and according to the different termination conditions of event execution,  //   types hook are derived. BailWaterfallLoop

Basic use:

const { SyncHook } = require('tapable');
const hook = new SyncHook(['name']);
hook.tap('hello', (name) => {
  console.log(`hello ${name}`);
});
hook.tap('hi', (name) => {
  console.log(`hi ${name}`);
});

hook.call('july');

// hello july
// hi july

summary:

tapable The basic logic is to first  tap register the corresponding  hook processing function through the method of the class instance, and then  call trigger the callback function through the method.

compiler

compiler The object contains all configuration information of the webpack environment, including options, loaders and plugins. It can be simply understood as a webpack instance. Represents the life cycle of the entire webpack from startup to shutdown .

compile Internal implementation of:

class Compiler extends Tapable {
  constructor(context) {
    super();
    this.hooks = {
      /** @type {SyncBailHook<Compilation>} */
      shouldEmit: new SyncBailHook(["compilation"]),
      /** @type {AsyncSeriesHook<Stats>} */
      done: new AsyncSeriesHook(["stats"]),
      /** @type {AsyncSeriesHook<>} */
      additionalPass: new AsyncSeriesHook([]),
      /** @type {AsyncSeriesHook<Compiler>} */
      ...
    };
    ...
}

Personal blog recommendation: boiled eggs blog

compile Inherited  tapable , and then bound an  hook object on the instance.

compilation

compilation The object contains the current module resources, compiled resources and changed files, etc. Only represents a new compilation .

compilation Implementation of:

class Compilation extends Tapable {
  /**   * Creates an instance of Compilation.   * @param {Compiler} compiler the compiler which created the compilation   */
  constructor(compiler) {
    super();
    this.hooks = {
      /** @type {SyncHook<Module>} */
      buildModule: new SyncHook(["module"]),
      /** @type {SyncHook<Module>} */
      rebuildModule: new SyncHook(["module"]),
      /** @type {SyncHook<Module, Error>} */
      failedModule: new SyncHook(["module", "error"]),
      /** @type {SyncHook<Module>} */
      succeedModule: new SyncHook(["module"]),
      /** @type {SyncHook<Dependency, string>} */
      addEntry: new SyncHook(["entry", "name"]),
      /** @type {SyncHook<Dependency, string, Error>} */
    };
  }
}

When running the webpack development environment middleware, whenever a file change is detected, a new one will be created  compilation, thus generating a new set of compiled resources. An  compilation object representing current module resources, build resources, changed files, and state information about tracked dependencies. compilation The object also provides many callbacks at key moments for the plug-in to choose to use when doing custom processing.

warm up

Write a very basic  plugin:

// 一个 JavaScript 命名函数。
function SimplePlugin() {}

// 在插件函数的 prototype 上定义一个 `apply` 方法。
SimplePlugin.prototype.apply = function (compiler) {
  // 指定一个挂载到 webpack 自身的事件钩子。
  compiler.plugin("webpacksEventHook", function (
    compilation /* 处理 webpack 内部实例的特定数据。*/,    callback  ) {
    console.log("This is an simple plugin!!!");

    // 功能完成后调用 webpack 提供的回调。
    callback();
  });
};

After webpack started, it did the following things:

  • Execute first in the process of reading configuration  new SimplePlugin(), initialize a SimplePlugin and obtain its instance.
  • After initializing  compiler the object, call it to  SimplePlugin.apply(compiler) pass in the object for the plugin instance  compiler .
  • After the plug-in instance obtains  compiler the object, it can  compiler.plugin("webpacksEventHook", function(compilation, callback){}) listen to the events broadcast by webpack and  compiler operate webpack through the object.

combat

Write a practical plugin below.

The role is to do something when webpack is about to close. For example, it tells whether the package is completed and whether the execution is successful. Or execute some  script script. We named it  AfterWebpackPlugin . The usage is as follows:

module.exports = {
  plugins: [
    // 分别传入成功和失败时的回调函数
    new AfterWebpackPlugin(
      () => {
        // 可以通知用户构建成功,执行发布脚本
      },
      (err) => {
        // 构建失败时,抛出异常
        console.error(err);
      }
    ),
  ],
};

The implementation process here requires the help of the following two hooks:

  • done : Occurs when webpack exits immediately after a successful build and output files.
  • failed : The build fails when a build exception occurs, and occurs when webpack exits immediately.

The implementation code is as follows:

class AfterWebpackPlugin {
  constructor(doneCb, failedCb) {
    // 传入回调函数
    this.doneCb = doneCb;
    this.failedCb = failedCb;
  }

  apply(compiler) {
    compiler.plugin("done", (res) => {
      // webpack 生命周期 `done` 中的回调
      this.doneCb(res);
    });
    compiler.plugin("failed", (err) => {
      // webpack 生命周期 `failed` 中的回调
      this.failedCb(err);
    });
  }
}

module.exports = AfterWebpackPlugin;

Development plug-in summary:

  • Pay attention to finding the appropriate hooks in the webpack life cycle to complete the function.
  • Be careful to understand the nuances of each hook in the webpack lifecycle.

expand

The events and explanations that occur during the webpack  output phase are as follows:

event name explain
should-emit All the files that need to be output have been generated, ask the plug-in which files need to be output, and which ones do not need to be output
emit After determining which files to output, execute the file output, you can get and modify the output content here
after-emit file output complete
done Successfully completed a complete compilation and output process
failed If an exception is encountered in the compilation and output process, causing webpack to exit, it will directly jump to this step, and the plug-in can obtain the specific error cause in this event

Well, the above is all the content of this article, I hope it will be helpful to you, and I hope you will give a lot of support to Code Farmer's House . Your support is the driving force for my creation! I wish you all a happy life!    

Guess you like

Origin blog.csdn.net/wuxiaopengnihao1/article/details/127920846