前言
身为一个前端仔,使用webpack那么久了,一直觉得webpack非常的厉害,尤其是它的扩展性,既是能兼容这种格式的文件的打包,又是能压缩打包体积,又是能起服务等等。这个强大的拓展性,主要是得益于webpack的两个配置项loader和plugin。等等,到这,打住!
聊到了这里,或许你们会觉得本文会讲webpack的使用啊或者原理等等,但不完全对,本文确实会说道webpack的一些原理,但严格来说不算是webpack原理,主要是深挖webpack的时候,看到了plugin这个配置项的实现,感觉非常有意思,从而想写几篇文章作为分享或者说记录。
实际上plugin并没有太多的好说的,webpakc的plugin属于是又复杂但又简单,复杂是指webpack提供了许许多多的hooks给你编写插件,简单是指plugin大致原理其实并不难。
所谓的plugin,其实就是暴露出去一堆的hooks,这些hooks的作用很简单,就是在打包的过程中的某一个时间点去执行,也可以理解成生命周期。而我们就是通过这些hooks给这个打包过程添加我们书写的代码,从而打造出一个目标产物。
好了,到这里差不多该请出今天的主角了------tapable!
webpack本质上是一种事件流的机制,他的工作流程(可以理解为每一个工作步骤都是可暴露出来的hook)就是将各种插件串联起来,而实现这一切的核心就是Tapable。
前排叠个甲,考虑到tapable这种东西大家日常工作中很少会去接触,所以本文主要是介绍tapable,下一篇文章会讲到tapable的实现,tapable的实现是一个非常有意思的东西,一定会涉及到很多人的知识盲区或者说在一定程度上打开大家的思维。
tapable
tapable就是一个提供了很多种hook的库。
tapable的hooks
js
const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
AsyncParallelHook,
AsyncParallelBailHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook,
} = require("tapable");
上面的这些hooks都分别是什么意思?这点很简单,他们就名字就是他们的意思。
- sync:同步
- async:异步
- bail:保释
- waterfall:瀑布
- loop:循环
- parallel:并行
- Series:串行
如果说知道单词的意思仍然不太懂他们都是什么样的hook,那么继续往下看。
tapable提供了这么多hook的同时,也给了这些hook做了很多种分类,最简单的一种分类当然是同步异步了,这个就不多说了。我们主要是了解针对hook的功能进行分类。
类别一:basic基础类别
这一类别的hook就是执行每一个事件函数,不关心返回值,分别有SyncHook、AsyncParallelHook、AsyncSeriesHook。
执行流程如下:
开始 -> 事件函数1 -> 事件函数2 ... -> 事件函数n -> 结束。
或许还是有点抽象,没关系,我们来简单使用下其中的一个hook就懂了。这里就体验下SyncHook吧。
可以不用专门下载tapable,下载webpack就会自带tapable。
js
const { SyncHook } = require('../tapable');
// 创建
// 这个name和age无实际意义,其实就是表示接受多少个参数而已
const hook = new SyncHook(['name', 'age']);
// 使用tap方法进行注册事件函数
hook.tap('1', (name, age) => {
console.log('1', name, age);
// 就算有返回值也会无视继续走下去
});
hook.tap('2', (name, age) => {
console.log('2', name, age);
});
hook.tap('3', (name, age) => {
console.log('3', name, age);
});
// 调用
hook.call('猪头', 18);
最后的执行结果:
结合图和代码,可以看出来这一类hook都非常简单,只要一直往前冲(不断的执行事件函数)就行了。
类别二:Bail保释类别
执行每一个事件函数,遇到第一个结果 result !== undefined
则返回,不再继续执行。有:SyncBailHook、AsyncSeriesBailHook, AsyncParallelBailHook。
执行流程如下:
以下是体验SyncBailHook的代码。
js
const { SyncBailHook } = require('tapable');
// 创建
// 这个name和age无实际意义,其实就是表示接受多少个参数而已
const hook = new SyncBailHook(['name', 'age']);
// 使用tap方法进行注册事件函数
hook.tap('1', (name, age) => {
console.log('1', name, age);
});
hook.tap('2', (name, age) => {
console.log('2', name, age);
// 这里遇到返回值就直接结束了
return '2';
});
hook.tap('3', (name, age) => {
console.log('3', name, age);
});
// 调用
hook.call('猪头', 18);
类别三:waterfall瀑布类别
如果前一个事件函数的结果 result !== undefined
,则 result 会作为后一个事件函数的第一个参数,有 SyncWaterfallHook,AsyncSeriesWaterfallHook。
执行流程如下:
以下是体验SyncWaterfallHook的代码。
js
const { SyncWaterfallHook } = require('tapable');
// 创建
// 这个name和age无实际意义,其实就是表示接受多少个参数而已
const hook = new SyncWaterfallHook(['name', 'age']);
// 使用tap方法进行注册事件函数
hook.tap('1', (name, age) => {
console.log('1', name, age);
});
hook.tap('2', (name, age) => {
console.log('2', name, age);
// 这里遇到返回值,就会将这个返回值替换掉下一个函数的第一个参数
return '2';
});
hook.tap('3', (name, age) => {
console.log('3', name, age);
});
// 调用
hook.call('猪头', 18);
类别四:loop循环类别
不停的循环执行事件函数,直到所有函数结果 result === undefined
,有 SyncLoopHook。
执行流程如下:
以下是体验SyncLoopHook的代码。
js
const { SyncLoopHook } = require('tapable');
// 创建
const hook = new SyncLoopHook();
// 使用tap方法进行注册事件函数
let count1 = 0, count2 = 0, count3 = 0;
hook.tap('1', () => {
console.log('1', 'count1', count1);
if (++count1 === 1) {
count1 = 0;
return;
}
return true;
});
hook.tap('2', () => {
console.log('2', 'count2', count2);
if (++count2 === 2) {
count2 = 0;
return;
}
return true;
});
hook.tap('3', () => {
console.log('3', 'count3', count3);
if (++count3 === 3) {
count3 = 0;
return;
}
return true;
});
// 调用
hook.call();
由于要所有函数都返回undefined才结束,所以以上会打印15行
这里毕竟涉及到循环,整个逻辑是有点绕的,大家可结合代码、结果、还有loop类别的描述捋清楚。
结尾
好了,对于tapable的介绍到这里就结束了,相信大家通过这篇小短文已经对tapable有一个简单的认识了。而本文的主旨就是让大家对tapable有一个简单的认识并不是说教会大家怎么使用tapable,只要有一个简单的了解就足够理解下一篇文章的内容了,而下一篇的内容才是真正的核心所在,所以大家结合下一篇文章享用更妙哦!
最后,创作不易,赏个赞啦🌹🌹🌹