当前位置: 首页 > Web前端 > JavaScript

说说Webpack插件系统Tapable

时间:2023-03-26 21:26:51 JavaScript

的关键实现Daniel:蛋哥,今天聊点什么?蛋先生:今天我们来聊聊webpack中插件系统实现的关键——Tapable大牛:Tapable?Mr.Egg:对,今天换个方式说吧,就说说你的一天Daniel:我的一天?蛋先生:首先,每个人的一天有几个阶段:早上、中午、下午、晚上。Tapable中的描述如下:const{SyncHook}=require("tapable");classMan{constructor(){this.hooks={morningHook:newSyncHook(),noonHook:newSyncHook(),afternoonHook:newSyncHook(),nightHook:newSyncHook(),};}startNewDay(){this.hooks.morningHook.call();this.hooks.noonHook.call();this.hooks.afternoonHook.call();这个.hooks.nightHook.call();}}大牛:SyncHook是什么?蛋蛋先生:别着急,以后你就会明白的。首先你是一个人。丹尼尔:不然呢?难不成还是禽兽?(`へ′)蛋先生:(lll¬ω¬)误会,看代码constdaniel=newMan();daniel.startNewDay();Daniel:哦,明白了。那么我一整天打算做什么呢?蛋先生:首先,早上,你早上要做三件事:起床、刷牙、吃早餐丹尼尔:就这些?还以为蛋先生有些意外:我不是在讲笑话╮(╯▽╰)╭,我只能讲代码,所以constdaniel=newMan();//MorninggetUpAction(daniel);brushTeethAction(daniel);eatBreakfastAction(daniel);daniel.startNewDay();functiongetUpAction(manInst){manInst.hooks.morningHook.tap("getUp",()=>console.log("Getup"));}functionbrushTeethAction(manInst)}{manInst.hooks.morningHook.tap("brushTeeth",()=>console.log("刷牙"));}functioneatBreakfastAction(manInst){manInst.hooks.morningHook.tap("eatBreakfast",()=>console.log("Eatbreakfast"));}Output:UpBrushTeethEatbreakfast大牛:我好像看到了什么,Man只是定义了生命周期钩子,但是每个阶段所做的是通过添加行为来灵活扩展(PS:你可以把这里的行为理解为外挂,就是为了配合这个脚本)蛋先生:对,没错。这里的起床、刷牙等行为是相互独立的,都是按同步顺序执行的,所以我们只使用普通的同步Hook,即SyncHook。类Man{constructor(){this.hooks={morningHook:newSyncHook(),...};}startNewDay(){this.hooks.morningHook.call();...}}丹尼尔:这个。hooks.morningHook.call()是早上通知本次循环开始,然后之前的Action已经通过manInst.hooks.morningHook.tap提前注册了本次循环要干什么,所以每个Action都忙于这个时间蛋先生:是的。你之前不是问过SyncHook吗?因为有同步和异步行为,Sync开头的Hook是同步执行的,Async开头的Hook是异步执行的。下个周期蛋蛋先生:对对对。一个循环阶段可以链接多个行为,一般先执行(SyncXXX和AsyncSeriesXXX),还有一种并发执行。当然,只有异步行为才能并发。接下来,让我们通过你的一天继续了解Tapable的各种Hooks等信息。大牛:好了,上午聊完了,中午干什么呢?伊戈先生:不不,现在还是早上。让我们稍微调整一下我们早上做的事情,起床,做早餐,吃早餐丹尼尔:嗯,还是老样子蛋蛋先生:你做早餐的时候搞砸了丹尼尔:啊,这么倒霉?那我要饿了X﹏Mr.X蛋:早餐吃不完,说明早餐需要中断。这时候就需要SyncBailHookconst{SyncBailHook}=require("tapable");classMan{constructor(){this.hooks={morningHook:newSyncBailHook(),...};}...}constdaniel=newMan();//MorninggetUpAction(daniel);makeBreakfastAction(daniel);eatBreakfastAction(daniel);daniel.startNewDay();functiongetUpAction(manInst){manInst.hooks.morningHook.tap("getUp",()=>console.log("起床"));}functionmakeBreakfastAction(manInst){manInst.hooks.morningHook.tap("makeBreakfast",()=>{console.log("做早餐,但失败了");returnfalse;});}functioneatBreakfastAction(manInst){manInst.hooks.morningHook.tap("eatBreakfast",()=>console.log("Eatbreakfast"));}输出结果Get起来做早餐,失败了大牛:嗯,吃不下算了,只能饿到中午了蛋先生:不吃早餐对身体不好,我改剧情。你设法做了早餐、牛奶、鸡蛋和面包。但是我们需要把做早餐的结果给早餐,这样早餐就有东西吃,那么我们可以使用SyncWaterfallHookconst{SyncWaterfallHook}=require("tapable");classMan{constructor(){this.hooks={morningHook:newSyncWaterfallHook(["breakfast"]),...};}...}functionmakeBreakfastAction(manInst){manInst.hooks.morningHook.tap("makeBreakfast",()=>{console.log("做早餐");return"牛奶、面包、鸡蛋";});}functioneatBreakfastAction(manInst){manInst.hooks.morningHook.tap("eatBreakfast",(breakfast)=>console.log("Eatbreakfast:",breakfast));}输出结果:起床做早餐吃早餐:牛奶,面包、蛋大牛:谢谢蛋哥,你对我真是太好了。我也吃完早饭了,快到中午了吧?蛋先生:对,中午了,你又在做饭丹尼尔:啊,我是吃货,我该做什么菜?蛋先生:你同时煮饭和汤。Daniel:Oneside...oneside...也就是同时做两件事Mr.Egg:是的,任何行为都可以同时做,当然是异步行为,那你可以用AsyncParallelHookconst{AsyncParallelHook}=require("tapable");classMan{constructor(){this.hooks={...noonHook:newAsyncParallelHook(),...};}asyncstartNewDay(){...awaitthis.hooks.noonHook.promise();...}}constdaniel=newMan();//Morning...//NoonsoupAction(daniel);cookRiceAction(daniel);daniel.startNewDay();...functioncookRiceAction(manInst){manInst.hooks。noonHook.tapPromise("cookRice",()=>{console.log("cookRicestarting...");returnnewPromise((resolve)=>{setTimeout(()=>{console.log("cookRicefinishing...");resolve();},800);});});}functionsoupAction(manInst){manInst.hooks.noonHook.tapPromise("soup",()=>{console.log("汤开始......”);returnnewPromise((resolve)=>{setTimeout(()=>{console.log("汤喝完了...");解决();},1000);});});}输出结果如下:soupstarting...cookRicestarting...cookRicefinishing...soupfinishing...Daniel:嗯,中午好像比早上顺利多了蛋先生:那就是下午开始学习番茄钟法下午四个小时Daniel:嗯,你知道我好学,真的蛋蛋先生太了解我了:因为一个番茄钟一直循环到4个小时,你可以使用SyncLoopHookconst{SyncLoopHook}=require("tapable");classMan{constructor(){this.hooks={...afternoonHook:newSyncLoopHook(),...};}asyncstartNewDay(){...this.hooks.afternoonHook.call();...}}constdaniel=newMan();//Morning...//Noon...//AfternoonstudyAction(daniel);restAction(daniel)daniel.startNewDay();...让leftTime=4*60;functionstudyAction(manInst){manInst.hooks.afternoonHook.tap("study",()=>{console.log("学习25分钟");leftTime-=25;});}functionrestAction(manInst){manInst.hooks.afternoonHook.tap("学习",()=>{控制台.log("休息5分钟");左时间-=5;if(leftTime<=0){console.log("tomatoStudy:finish");返回;}返回真;});}输出结果:study25minutesrest5minutesstudy25minutesrest5minutesstudy25minutesrest5minutesstudy25minutesrest5minutesstudy25minutesrest5minutesstudy25minutesrest5minutesstudy25minutesrest5minutesstudy25minutesrest5minutestomatoStudy:finish丹尼尔:学到头昏头脑的,晚上应该放松松了蛋先生:嗯,晚上可能打游戏看电影,看有没有朋友找你刷分。丹尼尔:哦,这要看情况,不是所有的动作都执行,对吧?HookMapconst{SyncHook,HookMap}=require("tapable");classMan{constructor(){this.hooks={...nightHook:newHookMap(()=>newSyncHook()),};}asyncstartNewDay(){...this.hooks.nightHook.for("无好友邀请").call();}}constdaniel=newMan();//Morning...//Noon...//Afternoon...//NightplayGameAction(daniel);watchMovieAction(daniel);daniel.startNewDay();...functionplayGameAction(manInst){manInst.hooks.nightHook.for("好友邀请").tap("playGame",()=>{console.log("玩游戏");});}functionwatchMovieAction(manInst){manInst.hooks.nightHook.for("nofriendinvitation").tap("watchMovie",()=>{console.log("watchmovie");});}output:watchmovie大牛:一天结束了,我们该说再见了蛋蛋先生:还没结束,你有记日记的好习惯,你做的每一件事都记得丹尼尔:什么都记得?这是流水帐。蛋先生:差不多,你觉得怎么记最好?Daniel:InterceptbeforeeverythingMr.Egg:真聪明,这里可以使用Interception...constdaniel=newMan();writeDiary(daniel);...daniel.startNewDay();...functionwriteDiary(manInst){constinterceptFn=(hookName)=>{return{tap:(tapInfo)=>{console.log(`writediary:`,tapInfo)}};};Object.keys(manInst.hooks).forEach((hookName)=>{if(manInst.hooks[hookName]instanceofHookMap){manInst.hooks[hookName].intercept({factory:(key,hook)=>{hook.拦截(整数erceptFn(挂钩名称));返回钩子},});}else{manInst.hooks[hookName].intercept(interceptFn(hookName));}});}输出结果:writediary:{type:'sync',fn:[Function],name:'getUp'}writediary:{type:'sync',fn:[Function],name:'makeBreakfast'}writediary:{type:'sync',fn:[Function],name:'eatBreakfast'}writediary:{type:'promise',fn:[Function],name:'soup'}写日记:{type:'promise',fn:[Function],name:'cookRice'}writediary:{type:'sync',fn:[Function],name:'study'}写日记:{type:'sync',fn:[Function],name:'study'}writediary:{type:'sync',fn:[Function],name:'study'}写日记:{type:'sync',fn:[Function],name:'study'}writediary:{type:'sync',fn:[Function],name:'study'}writediary:{type:'sync',fn:[Function],name:'study'}写日记:{type:'sync',fn:[Function],name:'study'}writediary:{type:'sync',fn:[Function],name:'study'}writediary:{type:'sync',fn:[Function],name:'watchMovie'}Daniel:日记写完了,没什么可做的。蛋先生:最后说说语境吧因为每个行为可能由不同的开发者提供,行为是独立的,但是有时候你想共享一些数据,比如你需要在这里共享你的个人信息,然后看最后一段代码,然后就可以了分散,然后坚持一会儿...constdaniel=newMan();writeDiary(daniel);...daniel.startNewDay();functiongetUpAction(manInst){manInst.hooks.morningHook.tap({name:"getUp",上下文:true,},(context)=>{console.log("Getup",context);});}...functionwriteDiary(manInst){constinterceptFn=(hookName)=>{返回{context:true,tap:(context,tapInfo)=>{context=context||{};context.userInfo={name:"丹尼尔",};}};};Object.keys(manInst.hooks).forEach((hookName)=>{if(manInst.hooks[hookName]instanceofHookMap){manInst.hooks[hookName].intercept({factory:(key,hook)=>{控制台.log(`[${hookName}][${key}]`);hook.intercept(interceptFn(hookName));returnhook;},});}else{manInst.hooks[hookName].intercept(interceptFn(hookName));}});}输出结果:起床{userInfo:{name:'daniel'}}Daniel:我困了,眼睛都睁不开了蛋先生:好了,你的一天结束了,再见Daniel:再见坚持读到这里的小伙伴们,你们会如何通过Tapable定制自己的一天呢?