Webpack和Tapable

我们知道webpack有两个非常重要的类:Compiler和Compilation

  • 它们通过注入插件的方式,来监听webpack的所有生命周期;
  • 插件的注入离不开各种各样的Hook,而它们的Hook是如何得到的呢?
  • 其实是创建了Tpable库中的各种Hook的实例;

所以,如果我们想要学习自定义插件,最好先了解一个库:Tapable

  • Tapable是官方编写和维护的一个库
  • Tapable是管理着需要的Hook,这些Hook可以被应用到我们的插件中

    Tapable

tapable的本质就是webpack官方提供的API

Tapable有哪些hook?

image.png

Tapable的Hook分类

  • 同步和异步的:
    • 以sync开头的,是同步的Hook
    • 以async开头的,两个事件处理回调,不会等待上一次处理回调结束后在执行下一次回调
  • 其他的类别
    • Bail:当有返回值时,就不会执行后续的事件触发了
    • Loop:当返回值为true,就会反复执行该事件,当返回值为undefined或者不返回内容,就退出事件
    • Waterfall:当返回值不为undefined时,会将这次返回的结果作为下次事件的第一个参数
    • Paraller:并行,会同时执行事件处理回调结束,才执行下一次事件处理回调
    • Series:串行,会等待上一次异步的Hook

      Hook的使用过程

第一步:创建Hook对象

  1. this.hooks = {
  2. asyncHook: new AsyncSeriesHook(["name", "age"])
  3. }

第二步:注册Hook中的事件

  1. this.hooks.asyncHook.tapPromise("event1", (name, age) => {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. console.log("event1", name, age);
  5. resolve();
  6. }, 2000);
  7. });
  8. });

第三步:触发事件

  1. emit() {
  2. this.hooks.asyncHook.promise("coder", 30).then(() => {
  3. console.log("第一次事件执行完成");
  4. });
  5. }

自定义Plugin

在之前的学习中,我们已经使用类非常多的Plugin:

  • CleanWebpackPlugin
  • HTMLWebpackPlugin
  • MiniCSSExtractPlugin
  • CompressionPlugin
  • 等等。。。

这些Plugin是如何被注册到webpack的生命周期中的呢?

  • 第一:在webpack函数的createCompiler方法中,注册了所有的插件;
  • 第二:在注册插件时,会调用插件函数或者插件对象的apply方法;
  • 第三:插件方法会接受compiler对象,我们可以通过compiler对象来注册Hook的事件;
  • 第四:某些插件也会传入一个compilation的对象,我们也可以监听compilation的Hook事件;

    开发自己的插件

    如何开发自己的插件呢?

  • 目前大部分插件都可以在社区中找到,但是推荐尽量使用在维护,并且经过社区验证的;

  • 这里我们开发一个自己的简单插件:将静态文件自动上传服务器中

    自定义Plugin过程

  1. 在项目中新建plugins文件夹,下面创建我们自己的的plugin插件

image.png

  1. 在webpack.config.js文件中引入我们创建的AutoUploadPlugin插件

    1. const path = require("path");
    2. const HtmlWebpackPlugin = require("html-webpack-plugin");
    3. const AutoUploadPlugin = require("./plugins/AutoUploadPlugin");
    4. module.exports = {
    5. entry: "./src/main.js",
    6. output: {
    7. path: path.resolve(__dirname, "./build"),
    8. filename: "bundle.js",
    9. },
    10. plugins: [new HtmlWebpackPlugin(), new AutoUploadPlugin()],
    11. };
  2. AutoUploadPlugin插件的具体内容

    1. class AutoUploadPlugin {
    2. apply(compiler) {
    3. compiler.hooks.afterEmit.tapAsync(
    4. "AutoUploadPlugin",
    5. (compilation, callback) => {
    6. console.log("内容已上传至服务器");
    7. callback();
    8. }
    9. );
    10. }
    11. }
    12. module.exports = AutoUploadPlugin;

    创建plugin插件最好是通过class,在其中实现一个apply方法,接受一个值为compiler的变量,然后通过compiler.hooks调用webpack的生命周期,这里因为我们的插件想要实现的效果是将打包后的文件上传到服务器,所以生命周期选择afterEmit(打包后)。