webpack源碼分析(一)— Tapable插件架構(gòu)

在前面的文章webpack不適合多頁面應(yīng)用?你寫的插件還不夠多中提到過述暂,webpack核心使用了Tapable實(shí)現(xiàn)事件的發(fā)布訂閱處理的插件架構(gòu)(Tapable中文文檔)畦韭,今天就具體來分析下webpack基于Tapable的插件架構(gòu)

找到代碼入口

  • 想必你已經(jīng)使用過npm install webpack命令下載過webpack艺配,那么在你的node_modules目錄下找到webpack转唉。
  • npm模塊的入口文件可以通過package.json中的"main": "lib/webpack.js"找到稳捆,當(dāng)你通過reqire引用模塊的時(shí)候,其實(shí)定位到的就是這個(gè)文件砖织。一般情況下侧纯,我們會(huì)在命令行直接使用webpack命令去執(zhí)行打包茂蚓,這個(gè)時(shí)候執(zhí)行的就是bin/webpack.js了,這個(gè)命令只是在調(diào)用lib/webpack.js之前處理一些命令行參數(shù)聋涨,殊途同歸。
  • 打開lib/webpack.js牍白。webpack.js除了使用exportPlugins導(dǎo)出很多插件類(方便外部調(diào)用)脊凰,最重要的事情就是創(chuàng)建compiler對(duì)象(如果options是數(shù)組的話茂腥,每個(gè)元素創(chuàng)建一個(gè))
    //創(chuàng)建compiler對(duì)象
    compiler = new Compiler();
    //后面這幾句代碼狸涌,得看了compiler再回來看看了
    compiler.options = options;
    compiler.options = new WebpackOptionsApply().process(options, compiler);
    new NodeEnvironmentPlugin().apply(compiler);
    compiler.applyPlugins("environment");
    compiler.applyPlugins("after-environment");

這個(gè)時(shí)候我們的視線得轉(zhuǎn)移到compiler上了

植入Tapable

打開lib/Compiler.js

    function Compiler() {

        //傳入作用域最岗,調(diào)用Tapable的構(gòu)造函數(shù)
        Tapable.call(this);

        this.outputPath = "";
        this.outputFileSystem = null;
        this.inputFileSystem = null;

        this.recordsInputPath = null;
        this.recordsOutputPath = null;
        this.records = {};

        this.fileTimestamps = {};
        this.contextTimestamps = {};

        this.resolvers = {
            normal: new Resolver(null),
            loader: new Resolver(null),
            context: new Resolver(null)
        };
        this.parser = new Parser();

        this.options = {};
    }
    module.exports = Compiler;

    //復(fù)制一份Tapable的原型
    Compiler.prototype = Object.create(Tapable.prototype);
    Compiler.prototype.constructor = Compiler;

如果你閱讀過Tapable中文文檔帕胆,你應(yīng)該對(duì)這個(gè)mix的方式不會(huì)陌生,tapable的原理其實(shí)也不復(fù)雜

聲明一個(gè)全局的變量this._plugins = {}懒豹,插件中使用plugin(name, fn)方法給事件name注冊(cè)處理方法fn,多次注冊(cè)形成了事件name的監(jiān)聽鏈,當(dāng)事件name觸發(fā)的時(shí)候蝴乔,執(zhí)行這些處理方法片酝。處理方法的執(zhí)行順序和執(zhí)行方式依據(jù)事件name的觸發(fā)方式的不同而不同

這個(gè)時(shí)候compiler已經(jīng)具備Tapable的所有屬性和方法了,我們?cè)倩氐絣ib/webpack.js來看看創(chuàng)建了Compiler對(duì)象后的幾行代碼

說實(shí)話不太欣賞這種在對(duì)象外面初始化的設(shè)計(jì)模式钠怯,讀代碼的時(shí)候你得跳來跳去,我更傾向于通過構(gòu)造函數(shù)傳入options鞠鲜,在對(duì)象內(nèi)進(jìn)行初始化工作宁脊。(僅代表個(gè)人的想法)

    //給對(duì)象參數(shù)賦值
    compiler.options = options;
    //傳入options和compiler執(zhí)行WebpackOptionsApply的process想法
    //這個(gè)方法對(duì)參數(shù)進(jìn)行了處理,并且注入了大量的插件
    compiler.options = new WebpackOptionsApply().process(options, compiler);
    //注冊(cè)nodeEveironmentPlugin插件
    new NodeEnvironmentPlugin().apply(compiler);
    //觸發(fā)environment和after-environment事件
    compiler.applyPlugins("environment");
    compiler.applyPlugins("after-environment");

webpack很多核心功能本身就是以插件的形式開發(fā)的贤姆,打開lib/WebpackOptionsApply就會(huì)發(fā)現(xiàn)榆苞,在這個(gè)方法中,除了處理參數(shù)霞捡,就是把一個(gè)個(gè)插件注冊(cè)到compiler中

compiler.applyPlugins("environment")以一種最簡(jiǎn)單的并行處理的方式去去觸發(fā)事件environment事件坐漏,所有注冊(cè)的處理方法并行執(zhí)行,相互獨(dú)立互不干擾,并且不需要給處理方法傳入?yún)?shù)赊琳。

而有些事件的觸發(fā)方式要復(fù)雜一些街夭,例如complier觸發(fā)emit的方式

    this.applyPluginsAsync("emit", compilation, function(err) {
        if(err) return callback(err);
        outputPath = compilation.getPath(this.outputPath);
        this.outputFileSystem.mkdirp(outputPath, emitFiles.bind(this));
    }.bind(this));

這段代碼:
觸發(fā)事件emit,傳入?yún)?shù)compilation對(duì)象躏筏,串行的調(diào)用注冊(cè)在事件emit上的處理函數(shù)(先入先出)板丽,倘若某一個(gè)處理函數(shù)報(bào)錯(cuò),則執(zhí)行傳入的function(err)趁尼,后續(xù)的處理函數(shù)將不被執(zhí)行埃碱,否則最后一個(gè)處理函數(shù)調(diào)用function()。插件注冊(cè)此類事件酥泞,處理函數(shù)需要調(diào)用callback砚殿,這樣才能保證監(jiān)聽鏈的正確執(zhí)行。所以為了在寫自定義插件的時(shí)候能正確的監(jiān)聽事件芝囤,非常有必要仔細(xì)讀Tapable中文文檔(雖然本文已經(jīng)多次提到這個(gè)文檔似炎,但是還是有必要再進(jìn)行一次提醒)

webpack中另外一個(gè)重要的對(duì)象compilation使用了同樣的方式植入了tapable

總結(jié)

咱們分析webpack源碼主要有兩個(gè)原因:一是為了學(xué)習(xí)優(yōu)秀的代碼的設(shè)計(jì)方法,二是為了編寫webpack自定義插件的時(shí)候能夠游刃有余凡人。不管從哪一點(diǎn)來說名党,Tapable面向切面的插件思想,都是值得我們琢磨的(在我的一個(gè)項(xiàng)目中還真的從webpack把Tapable借鑒過來了)

后續(xù)會(huì)繼續(xù)更新對(duì)webpack源碼的進(jìn)一步分析挠轴,歡迎關(guān)注传睹,共同學(xué)習(xí)。有問題請(qǐng)?jiān)u論或發(fā)簡(jiǎn)信岸晦,如果你覺得文章對(duì)你有所幫助欧啤,請(qǐng)不要吝惜你的喜歡,當(dāng)然启上,給我打賞我也不會(huì)客氣的~~邢隧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冈在,隨后出現(xiàn)的幾起案子倒慧,更是在濱河造成了極大的恐慌,老刑警劉巖包券,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纫谅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡溅固,警方通過查閱死者的電腦和手機(jī)付秕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侍郭,“玉大人询吴,你說我怎么就攤上這事掠河。” “怎么了猛计?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵唠摹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我有滑,道長(zhǎng)跃闹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任毛好,我火速辦了婚禮望艺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肌访。我一直安慰自己找默,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布吼驶。 她就那樣靜靜地躺著惩激,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蟹演。 梳的紋絲不亂的頭發(fā)上风钻,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音酒请,去河邊找鬼骡技。 笑死,一個(gè)胖子當(dāng)著我的面吹牛羞反,可吹牛的內(nèi)容都是我干的布朦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼昼窗,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼是趴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起澄惊,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤唆途,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掸驱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窘哈,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年亭敢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片图筹。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帅刀,死狀恐怖让腹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扣溺,我是刑警寧澤骇窍,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站锥余,受9級(jí)特大地震影響腹纳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驱犹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一嘲恍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雄驹,春花似錦佃牛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔬将,卻和暖如春爷速,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背霞怀。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工惫东, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人里烦。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓凿蒜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親胁黑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子废封,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • GitChat技術(shù)雜談 前言 本文較長(zhǎng),為了節(jié)省你的閱讀時(shí)間丧蘸,在文前列寫作思路如下: 什么是 webpack漂洋,它要...
    蕭玄辭閱讀 12,697評(píng)論 7 110
  • 說在前面:這些文章均是本人花費(fèi)大量精力研究整理,如有轉(zhuǎn)載請(qǐng)聯(lián)系作者并注明引用力喷,謝謝本文的受眾人群不是webpack...
    RockSAMA閱讀 6,927評(píng)論 2 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理刽漂,服務(wù)發(fā)現(xiàn),斷路器弟孟,智...
    卡卡羅2017閱讀 134,667評(píng)論 18 139
  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺贝咙,特此分享以備自己日后查看,也希望更多的人看到...
    小小字符閱讀 8,171評(píng)論 7 35
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,823評(píng)論 6 342