• webpack原理篇(五十三):Tapable插件架构与Hooks设计


    说明

    玩转 webpack 学习笔记

    compiler

    上一节里面有个重要的东西就是 compiler

    在这里插入图片描述

    下面找一下这个东东,在 my-project\node_modules\webpack\lib\webpack.js 里面可以看到

    在这里插入图片描述
    这里的 Compiler 跟 MultiCompiler 分别引用了不同的 js

    const Compiler = require("./Compiler");
    const MultiCompiler = require("./MultiCompiler");
    
    • 1
    • 2

    找到 my-project\node_modules\webpack\lib\Compiler.js

    在这里插入图片描述
    可以看到 Compiler 继承了 Tapable
    在这里插入图片描述

    Webpack 的本质

    Webpack 可以将其理解是一种基于事件流的编程范例,一系列的插件运行。

    核心对象 Compiler 继承 Tapable:

    class Compiler extends Tapable {
    	// ... 
    }
    
    • 1
    • 2
    • 3

    核心对象 Compilation 继承 Tapable

    class Compilation extends Tapable {
    	// ... 
    }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    Tapable 是什么?

    Tapable 是一个类似于 Node.js 的 EventEmitter 的库, 主要是控制钩子函数的发布与订阅,控制着 webpack 的插件系统。

    Tapable 库暴露了很多 Hook(钩子)类,为插件提供挂载的钩子

    const {
    	SyncHook, // 同步钩子
    	SyncBailHook, // 同步熔断钩子(遇到 return 直接返回)
    	SyncWaterfallHook, // 同步流水钩子(结果可以传递给下一个插件)
    	SyncLoopHook, // 同步循环钩子
    	AsyncParallelHook, // 异步并发钩子
    	AsyncParallelBailHook, // 异步并发熔断钩子
    	AsyncSeriesHook, // 异步串行钩子
    	AsyncSeriesBailHook, // 异步串行熔断钩子
    	AsyncSeriesWaterfallHook // 异步串行流水钩子
    } = require("tapable");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Tapable hooks 类型

    typefunction
    Hook所有钩子的后缀
    Waterfall同步方法,但是它会传值给下一个函数
    Bail熔断:当函数有任何返回值,就会在当前执行函数停止
    Loop监听函数返回true表示继续循环,返回undefine表示结束循环
    Sync同步方法
    AsyncSeries异步串行钩子
    AsyncParallel异步并行执行钩子

    Tapable 的使用:new Hook 新建钩子

    Tapable 暴露出来的都是类方法,new 一个类方法获得我们需要的钩子

    class 接受数组参数 options ,非必传。类方法会根据传参,接受同样数量的参数。

    const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);
    
    • 1

    Tapable 的使用:钩子的绑定与执行

    Tabpack 提供了同步 & 异步绑定钩子的方法,并且他们都有绑定事件和执行事件对应的方法。

    Async*Sync*
    绑定: tapAsync/tapPromise/tap绑定: tap
    执行: callAsync/promise执行: call

    Tapable 的使用:hook 基本用法示例

    const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);
    // 绑定事件到webapck事件流
    hook1.tap('hook1', (arg1, arg2, arg3) => console.log(arg1, arg2, arg3)) //1,2,3
    // 执行绑定的事件
    hook1.call(1,2,3)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Tapable 的使用:实际例子演示

    新建项目

    1、我们先新建一个项目 tapable-kaimo,然后执行下面命令

    npm init -y
    npm i tapable
    
    • 1
    • 2

    在这里插入图片描述

    先添加一个 index.js 文件,输入下面代码

    const {
        SyncHook
    } = require('tapable');
    
    const hook = new SyncHook(["arg1", "arg2", "arg3"]);
    
    hook.tap("hook1", (arg1, arg2, arg3) => {
        console.log(arg1, arg2, arg3);
    });
    
    hook.call(1, 2, 3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行 node index.js 结果如下

    在这里插入图片描述

    实现下面例子

    定义一个 Car 方法,在内部 hooks 上新建钩子。分别是同步钩子 accelerate、brake( accelerate 接受一个参数)、异步钩子 calculateRoutes。

    使用钩子对应的绑定和执行方法

    calculateRoutes 使用 tapPromise 可以返回一个 promise 对象

    新建一个 car.js 文件,添加下面代码

    const {
        SyncHook,
        AsyncSeriesHook
    } = require('tapable');
    
    // 创建 Car 类
    class Car {
        constructor() {
            this.hooks = {
                accelerate: new SyncHook(['newSpeed']), // 加速 hook
                brake: new SyncHook(), // 刹车 hook
                calculateRoutes: new AsyncSeriesHook(['source', 'target', 'routesList']) // 计算路径 hook
            }
        }
    }
    
    // 实例化 Car
    const kaimoCar = new Car();
    
    // 绑定同步钩子
    kaimoCar.hooks.brake.tap('WarningLampPlugin', () => {
        console.log('WarningLampPlugin');
    })
    
    // 绑定同步钩子 并传参
    kaimoCar.hooks.accelerate.tap('LoggerPlugin', newSpeed => {
        console.log(`Accelerate to ${newSpeed}`);
    })
    
    // 绑定一个异步 Promise 钩子
    kaimoCar.hooks.calculateRoutes.tapPromise('calculateRoutes tapPromise', (source, target, routesList, callback) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log(`tapPromise to ${source} ${target} ${routesList}`);
                resolve()
            }, 1000)
        })
    })
    
    /*****************下面开始执行***************/ 
    
    kaimoCar.hooks.brake.call();
    kaimoCar.hooks.accelerate.call(313);
    
    console.time('kaimoCar cost');
    
    kaimoCar.hooks.calculateRoutes.promise('Async', 'hook', 'kaimo demo').then(() => {
        console.timeEnd('kaimoCar cost');
    }, err => {
        console.error(err);
        console.timeEnd('kaimoCar cost');
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    运行命令执行 node car.js,结果如下

    在这里插入图片描述

  • 相关阅读:
    ubuntu内核更改
    人工智能5:构建基于iris 数据集的 SVM 分类模型,含有 iris.csv
    【喜报】冲量在线荣获首届“创领浦东”创新创业大赛三等奖!
    @RequiredArgsConstructor(onConstructor=@_(@Autowired))是什么语法?
    《中国垒球》:跨界互动·全明星赛
    MySQL数据库之多表查询
    泰迪杯A题通讯产品销售和盈利能力分析一等奖作品
    Mini小主机All-in-one搭建教程1-安装Esxi7.0虚拟机系统
    PTA:7-1 线性表的合并
    回顾封装、继承和多态的概念,并给出相关示例
  • 原文地址:https://blog.csdn.net/kaimo313/article/details/126459516