当前位置: 首页 > news >正文

webpack plugin

webpack plugin

webpack完成的复杂炫酷的功能依赖于插件机制,webpack的插件机制依赖于核心的库, tapable
tapable是一个类似于nodejs的eventEmitter的库, 主要是控制钩子函数的发布喝定于,当时,tapable提供您的hook机制比较全面,分为同步和异步两个大类, 根据事件执行的终止条件的不同

const {SyncHook}= require('tapable')
const hook = new SyncHook(['arg1', 'arg2'])
hook.tap('a', function(arg1, arg2) {console.log('ar')
})
hook.tap('b',function(arg1, arg2) {console.log('b')
})
hook.call(1, 2)

BasicHook: 执行每一个,不关心函数的返回值,有SyncHook, AsyncParallelHook, AsyncSeriesHook
BailHook: 顺序执行hook,遇到第一个结果result!=undefined则返回,不在执行
SyncBailHook, AsyncSeriesBailHook, AsyncParallelBailHook

tapable => sync => SyncHook=> SyncBailHook=> SyncWaterfallHook=> SyncLoopHook=> Async => AsyncParallel => AsyncParallelHook => AsyncParallelBailHook=> AsyncSeries   => AsyncSeriesHook=> AsyncParallelBailHook=> AsyncSeriesLoopHook=> AsyncSeriesWaterfallHook

每个Hook的用法
Basic: 不关心回调函数返回值,[SyncHook, AsyncParallelHook, AsyncSeriesHook]
Bail: 只要其中一个监听函数的返回值,不为undefined,则终止执行。 [SyncBailHook, AsyncParallelHook, AsyncSeriesBailHook]
waterfall: 前一个监听函数的返回值部位undefined,则作为下一个监听函数的第一个参数
[SyncWaterfallHook, AsyncSeriesWaterfallHook]
Loop: 如果有一个监听函数的返回值不为undefined, 则终止向下执行,从头开始执行,直到所有监听函数的返回值为undefined。[SyncLoopHook, AsyncSeriesLoopHook]~

```javascript
const {SyncHook} = require('tapable')
let hook = new SyncHook(['name'])
hook.tap('demo', function(params) {console.log('demo', params)
})
hook.tap('demo2', function(params) {console.log('demo2', params)return true
})
hook.tap('demo3', function(params) {console.log('demo3', params)
})
hook.call('hello SyncHook')
class SyncHook {constructor(args = []) {this._args = argsthis.tasks = []}tap(name, task) {this.tasks.push(task)}call(...args) {const params = args.slice(0, this._args.length)this.tasks.forEash(task => task(...params))}
}
const {SyncBailHook} = require('tapable')
let hook = new SyncBailHook(['name'])
hook.tap('demo', function(params) {console.log('demo', params)
})
hook.tap('demo2', function(params) {console.log('demo2', params)return true
})
hook.tap('demo3', function(params) {console.log('demo3', params)
})
hook.call('hello SyncBailHook')

SyncBailHook钩子遇到回调函数中返回结果不为undefined的时候,则跳过下面所有的逻辑

class SyncBailHook {constructor(args) {this._args = _argsthis.tasks = []}tap(name, task) {this.tasks.push(task)}call() {const args = Array.from(arguments).slice(0, this._args.length)for(let i = 0; i < this.tasks.length; i++) {if(result !== undefiend) {break}}}
}

SyncWaterfallHook

const {SyncWaterfallHook} = require('tapable')
const hook = new SyncWaterfallHook(['author', 'age'])
hook.tap('测试1', (params1, params2) => {console.log('测试1接受的参数', params1, params2)
})
hook.tap('测试2', (params1, params2) => {console.log('测试2接受的参数', params1, params2)
})
hook.tap('测试3',(params1, params2) => {console.log('测试3接受的参数', params1, params2)
})
hook.call('嘎嘎嘎', '99')

syncWaterfallHook是一个同步的,瀑布类型的hook,瀑布类型的钩子就是如果前一个事件的函数结果部位undefined,则result会作为后一个事件函数的第一个参数,也就是上一个函数的执行结果会成为下一个函数的参数

const {SyncLoopHook} = require('tapable')
const hook = new SyncLoopHook([])
let count = 5
hook.tap('测试1', () => {console.log("测试1里面的count", count)if([1, 2, 3].includes(count) {return undefiend} else {count--return "123"})
}) 
hook.tap('测试2', () => {console.log("测试2里面的count", count)if([1, 2].includes(count) {return undefiend} else {count--return "123"})
})
hook.tap("测试3", () => {console.log("测试3里面的count",count)if([1].includes(count) {return undefiend} else {count--return "123"})
})
hook.call()

syncLoophook=>asyncparallelHook是一个异步并行,基本类型的Hook, 与同步不同的地方在于

  • 会同时开启多个异步任务,而且需要通过tapSaync
const {AsyncParallelHook} = require("tapable")
const hook = new AsyncParallelHook(['author', 'age'])
console.log('time')
hook.tapAsync('测试1', (params1, params2) {setTimeout(() => {console.log('测试1接受的参数', params1, params2)callback()}, 2000)
})
hook.tapAsync('测试2', (params1, params2, callback) {console.log("测试2接受的参数", params1, params2)callback()
})
hook.tapAsync('测试3',(params1, params2,callback) => {console.log("测试3接受的参数", params1, params2)callback()
})
hook.callAsync('嘎嘎嘎', "99",(err, result) => {console.log("这个是成功的回调",err, result)console.timeEnd("time")
})

AsyncParallelBailHook是一个异步并行,保险类型的hook,只要其中一个有返回值, 就会执行callAsync中的回调

const {AsyncParallelHook} = require('tapable')
const hook = new AsyncParallelBailHook(['author', 'age'])
console.time('time')
hook.tapAsync('测试1', (params1, params2, callback) => {console.log('测试1接受的参数',params1, params2)setTimeout(() => {callback()},1000)
})
hook.tapAsync("测试2", (params1,params2,callback) => {console.log('测试2接受的参数',params1, params2) setTimeout(() => {callback(null, '测试2有返回值')}, 2000)
})
hook.tapAsync('测试3', (params1, params2, callback) => {console.log('测试3接受的参数',params1, params2)setTimeout(()=> {callback(null, '测试3有返回值')}, 3000)
})
hook.callAsync("嘎嘎嘎", "99", (err, result) => {//等全部都完成了才会走到这里来console.log("这是成功后的回调", result);console.timeEnd("time");
});

AsyncSeriesHook是一个异步的,串行的类型的hook,只有前面的执行完成了,后面的才会执行

const {AsyncSeriesHook} = require('tapable')
const hook = new AsyncSeriesHook(['author', 'age'])
console.time('time')
hook.tapAsync('测试1' (params1, params2, callback) => {console.log('测试1接受的参数', params1, params2)setTimeout(() => {callback()}, 1000)
})
hook.tapAsync('测试2' (params1, params2, callback) => {console.log('测试2接受的参数', params1, params2)setTimeout(() => {callback()}, 2000)
})
hook.tapAsync('测试3' (params1, params2, callback) => {console.log('测试3接受的参数', params1, params2)setTimeout(() => {callback()}, 3000)
})
console.timeEnd()

AsyncSeriesBailHook 是一个异步串行,保险类型的hook,在串行的执行过程中,只要其中一个有返回值,后面就不会执行

const {AsyncSeriesBailHook} = require('tapable')
const hook = new AsyncParallelHook(['author', 'age'])
hook.tapAsync('测试1',(params1, params2, callback) => {console.log('测试1接受的参数',params1, params2)setTimeout(() => {callback()}, 1000)
})
hook.tapAsync('测试2',(params1, params2,callback) {console.log('测试2接受的参数',params1, params2)setTimeout(() => {callback()}, 2000)
}) 
hook.tapAsync('测试3',(params1, params2,callback) {console.log('测试3接受的参数',params1, params2)setTimeout(() => {callback()}, 3000)
}) 
hook.callAsync("嘎嘎嘎", "99", (err, result) => {//等全部都完成了才会走到这里来console.log("这是成功后的回调", result);console.timeEnd("time");
});

AsyncSeriesWaterfallHook是一个异步串行,瀑布类型的hook, 如果前一个事件函数的结果result!==undefined,则result会作为后一个事件函数的第一个参数,也就是上一个函数的执行结果会称为下一个函数的参数

const {AsyncSeriesWaterfallHook} = require('tapable')
const hook = new AsyncSeriesWaterfallHook(['author', 'age'])
console.time('time')
hook.tapAsync("测试1", (params1, params2, callback) => {console.log('测试1接受的参数', params1, params2)setTimeout(() => {callback(() => {callback(null, '2')}, 1000)})
})
hook.tapAsync("测试2", (params1, params2, callback) => {console.log('测试2接受的参数', params1, params2)setTimeout(() => {callback(null, '3')},2000)
})
hook.tapAsync("测试3", (param1, param2, callback) => {console.log("测试3接收的参数:", param1, param2);setTimeout(() => {callback(null, "4");}, 3000);
});hook.callAsync("嘎嘎嘎", "99", (err, result) => {//等全部都完成了才会走到这里来console.log("这是成功后的回调", err, result);console.timeEnd("time");
});

Tapable拦截器
Tapable提供的所有的hook都支持注入Interception,它和Axios的拦截器的效果非常类似,可以通过拦截器对整个Tapable发布/订阅流程进行监听,从而触发对应的逻辑

const hook = new SyncHook(['arg1', 'arg2', 'arg3'])
hook.intercept({// 每次调用hook实例的tap,方法注册回调函数的时候,就会调用该方法// 并且接受tap作为参数,还可以对tap进行修改register: (tapInfo) => {console.log(`${tapInfo.name} is doing its job`)return tapInfo},// 通过hook实例对象上的call方法时候触发拦截器call: (arg1, arg2, arg3) => {console.log('starting to calculate routes')}// 在调用被注册的每一个事件函数之前执行tap: (tap) => {console.log(tap, 'tap'))}// loop类型钩子中,每个事件函数被调用前触发拦截器方法 loop:(...args) => {console.log(args, 'loop')}
})

相关文章:

webpack plugin

webpack plugin webpack完成的复杂炫酷的功能依赖于插件机制&#xff0c;webpack的插件机制依赖于核心的库&#xff0c; tapable tapable是一个类似于nodejs的eventEmitter的库&#xff0c; 主要是控制钩子函数的发布喝定于&#xff0c;当时&#xff0c;tapable提供您的hook机…...

【busybox记录】【shell指令】date

目录 内容来源&#xff1a; 【GUN】【date】指令介绍 【busybox】【date】指令介绍 【linux】【date】指令介绍 使用示例&#xff1a; 打印前天的日期: 打印三个月零一天后的日期: 打印当年圣诞节的年数: 打印当前的全月名称和月的日期: 要打印一个没有前导零的日期&…...

同态加密和SEAL库的介绍(八)性能

本篇会对比三种加密方案&#xff0c;同时每种方案配置三种参数。即九种情况下的各个操作的性能差异&#xff0c;为大家选择合适的方案和合适的参数提供参考。表格中所有时长的单位均为微妙&#xff0c;即 。 当然数据量比较大&#xff0c;为了方便大家查找&#xff0c…...

华为OD-D卷数的分解

给定一个正整数n&#xff0c;如果能够分解为m(m > 1)个连续正整数之和&#xff0c;请输出所有分解中&#xff0c;m最小的分解。 如果给定整数无法分解为连续正整数&#xff0c;则输出字符串"N"。 输入描述: 输入数据为一整数&#xff0c;范围为&#xff08;1, 2^3…...

rk3588 low_delay_net_display注意事项

low_delay_net_display例子默认只支持YUV420和RGB888,如果需要支持YUV422&#xff0c;请添加下面部分&#xff1a; rk3588_nvr/build/app/low_delay_net_display$ git diff v4l2HdmiRX.cpp diff --git a/app/low_delay_net_display/v4l2HdmiRX.cpp b/app/low_delay_net_displa…...

Spring Boot 快速入门样例【后端 3】

Spring Boot 入门&#xff1a;从零到一构建你的第一个应用 Spring Boot 作为一个流行的Java框架&#xff0c;以其“习惯优于配置”的理念极大地简化了Spring应用的开发和部署过程。本文将带你一步步创建一个简单的Spring Boot应用&#xff0c;从环境准备到项目创建&#xff0c;…...

Linux云计算 |【第二阶段】NETWORK-DAY2

主要内容&#xff1a; VLAN技术、TRUNK模式、链路聚合、路由器 一、VLAN技术应用 广播域指接受同样广播消息的节点的集合&#xff0c;如在该集合中的任何一个节点传输一个广播帧&#xff0c;则所有其它能收到这个帧的节点都被认为是该广播帧的一部分&#xff1b; 交换机的所有…...

Java面试题(基础篇)③

目录 一&#xff0c; 与 equals 的区别&#xff1f; 二&#xff0c;接口和抽象类的区别&#xff1f; 三&#xff0c;请说出几个常见的异常&#xff1f; 四&#xff0c;请问你对Java 反射有了解吗&#xff1f; 五&#xff0c;浅拷贝和深拷贝区别&#xff1f; 一&#xff0c…...

Qt动态调用 - QMetaObject::invokeMethod

QMetaObject::invokeMethod 动态调用是 Qt 的元对象系统的一项强大功能&#xff0c;它允许在运行时通过名称调用槽函数、信号和普通成员函数。 这种能力对于构建灵活和可扩展的应用程序非常有用&#xff0c;比如插件系统或脚本接口。 动态调用方法 Qt 提供了 QMetaObject::i…...

html+css+js网页设计 星享咖啡6个页面(带js) ui还原度90%

htmlcssjs网页设计 星享咖啡6个页面&#xff08;带js&#xff09; ui还原度90% 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等…...

docker上传镜像至阿里云

1、安装wsl2 WSL2安装&#xff08;详细过程&#xff09; 2、安装docker Docker在Windows下的安装及使用 3、创建私人阿里云镜像库 如何创建私人阿里云镜像仓库&#xff1f;&#xff08;保姆级&#xff09; 4、如何删除容器 (1) 查找正在使用该图像的容器 docker ps -a --filte…...

POS刷卡开发源码之语音播报-CyberWinApp-SAAS 本地化及未来之窗行业应用跨平台架构

一、终端语音提醒的好处 1. 增强信息传递的有效性&#xff1a;在人们忙碌或者注意力分散时&#xff0c;语音提醒能够直接穿透噪音和干扰&#xff0c;确保重要信息被准确接收。 2. 提高操作的便捷性&#xff1a;用户无需停下手中的工作去查看屏幕或阅读文字&#xff0c;直接通过…...

jupyter notebook魔法命令

%xmode 魔法命令来控制异常报告&#xff1a; 输入魔法命令&#xff1a;在 IPython 或 Jupyter Notebook 的一个新单元格中&#xff0c;输入以下命令之一来设置异常报告模式&#xff1a; 切换到 Plain 模式&#xff08;简洁输出&#xff09;&#xff1a; %xmode Plain切换回 Con…...

Mysql事件

1&#xff1a;查询全局事件开关是否启动 SHOW VARIABLES LIKE %sche%; 关闭状态&#xff01;&#xff01;&#xff01;去开启如果已开启忽略 set global event_scheduler ON; ojbk 2&#xff1a;创建事件 step1&#xff1a; 链接打开自己的数据库 step2&#xff1a; 找…...

Unity Console 窗口输出对齐

起因&#xff1a;做了个工具在console窗口罗列一些信息&#xff0c;基本结构是 [ 文件名 &#xff1a;行号 ]&#xff0c;因为文件&#xff0c;行号长度不一&#xff0c;想要做到如下效果。 初步尝试&#xff0c;用以下方法&#xff1a; string format "{0,-10} …...

leetcode198_打家劫舍

思路 动态规划 func rob(nums []int) int {if len(nums) < 2 {return nums[0]}// dp[i] 表示到第i家为止&#xff0c;小偷能够偷窃到的最高金额dp : make([]int, len(nums))dp[0] nums[0]dp[1] max(nums[0], nums[1])for i:2; i<len(nums); i {if nums[i] dp[i-2] &…...

C# 串口通讯怎么防止数据丢失

串口通信&#xff08;Serial Communication&#xff09;是计算机与设备之间进行数据交换的一种方式。在C#中进行串口通信时&#xff0c;防止数据丢失可以采取以下一些措施&#xff1a; 1.校验和&#xff08;Checksum&#xff09;&#xff1a;在发送数据时&#xff0c;计算数据的…...

【机器学习】BP神经网络中的链式法则:解开智能背后的数学奥秘

在浩瀚的机器学习领域中&#xff0c;BP&#xff08;反向传播&#xff09;神经网络如同一座桥梁&#xff0c;连接着复杂的数据世界与智能的彼岸。而这座桥梁的基石之一&#xff0c;便是链式法则&#xff08;Chain Rule&#xff09;——一个看似简单却蕴含无限智慧的数学原理。今…...

MyBatis 基本操作 - 注解版

目录 一&#xff0c;查询 - select 1.1 全列查询 1.2 指定列查询 1.3 赋值问题 方法一&#xff1a;起别名 方法二&#xff1a;结果映射 方法三&#xff1a;添加配置 二&#xff0c;新增 - Insert 2.1 使用对象插入 2.2 获取主键 三&#xff0c;删除 - Delete 四&am…...

专业比例阀放大器配套选型

比例阀放大器作为液压系统中的关键组件&#xff0c;其技术选型对于保障系统的精确控制、稳定性和长期可靠性至关重要。下面将深入探讨比例阀放大器的技术选型要点&#xff0c;确保选型能满足特定的应用需求和系统性能要求&#xff1a; 兼容性与安装方式 阀型匹配&#xff1a;…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...