打开compileclass Compiler extends Tapable { constructor(context) { super(); this.hooks = { //… } }}Compiler是个构造函数,定义了一些静态属性和方法我们先看 TapableTapable在node_modules插件下git地址上面写的解释Just a little module for plugins就跟没写一样在lib/index.js 文件下exports.__esModule = true;exports.Tapable = require("./Tapable");exports.SyncHook = require("./SyncHook");exports.SyncBailHook = require("./SyncBailHook");exports.SyncWaterfallHook = require("./SyncWaterfallHook");exports.SyncLoopHook = require("./SyncLoopHook");exports.AsyncParallelHook = require("./AsyncParallelHook");exports.AsyncParallelBailHook = require("./AsyncParallelBailHook");exports.AsyncSeriesHook = require("./AsyncSeriesHook");exports.AsyncSeriesBailHook = require("./AsyncSeriesBailHook");exports.AsyncSeriesWaterfallHook = require("./AsyncSeriesWaterfallHook");exports.HookMap = require("./HookMap");exports.MultiHook = require("./MultiHook");我们看到输出的一些对象方法每一个对应一个模块而在webpakck Compiler.js下引入的下面const { Tapable, SyncHook, SyncBailHook, AsyncParallelHook, AsyncSeriesHook} = require(“tapable”);so,我们先研究引入的对象tap 的英文单词解释,除了最常用的 点击 手势之外,还有一个意思是 水龙头 进一步可以理解为tapable是管理事件流的意思借用网上的一张图,tapable是事件管家之所以名称有差距,是版本问题导致的,目前的是1.1.0版本,我们看看git果然证明了v0.2.8以前的全部都是下图函数所示????看个源码好艰辛我们还是看一看git上的readme.md文档吧class Car { constructor() { this.hooks = { accelerate: new SyncHook([“newSpeed”]), break: new SyncHook(), calculateRoutes: new AsyncParallelHook([“source”, “target”, “routesList”]) }; } /* … /}const myCar = new Car();// 可以理解为trigger触发,consument是消费者的意思// Use the tap method to add a consumentmyCar.hooks.break.tap(“WarningLampPlugin”, () => warningLamp.on());myCar.hooks.accelerate.tap(“LoggerPlugin”, newSpeed => console.log(Accelerating to ${newSpeed}));//异步方法myCar.hooks.calculateRoutes.tapAsync(“BingMapsPlugin”, (source, target, routesList, callback) => { bing.findRoute(source, target, (err, route) => { if(err) return callback(err); routesList.add(route); // call the callback callback(); });});// 异步方法// You can still use sync pluginsmyCar.hooks.calculateRoutes.tap(“CachedRoutesPlugin”, (source, target, routesList) => { const cachedRoute = cache.get(source, target); if(cachedRoute) routesList.add(cachedRoute);})上面写的tap对应如下的call方法class Car { / … */ setSpeed(newSpeed) { this.hooks.accelerate.call(newSpeed); } useNavigationSystemPromise(source, target) { const routesList = new List(); return this.hooks.calculateRoutes.promise(source, target, routesList).then(() => { return routesList.getRoutes(); }); } useNavigationSystemAsync(source, target, callback) { const routesList = new List(); this.hooks.calculateRoutes.callAsync(source, target, routesList, err => { if(err) return callback(err); callback(null, routesList.getRoutes()); }); }}很像监听者模式,当你call是执行你on的函数,也就是按照这个文档所说的running your plugins这就是这个插件所做的,当然这个插件还做了异步处理等一些其他的事情之所以用这个插件,是因为能很好的处理时间流异步回调的情况具体的Tapable如何实现,很复杂webpack很多核心功能本身是以插件的形式开发的参考文章Webpack 源码(一)—— Tapable 和 事件流浅析webpack源码之Tapable介绍git文档 Tapable中文文档webpack源码分析(一)— Tapable插件架构探索webpack源码(三)— Tapable插件使用 2018-04-10话说看了这么多,感觉还是很凌乱,Tapable到底是怎么做的,以及优点在哪里,我们往下读,也许读着读着就会豁然开朗,所以标题就从Tapable详解到粗解