摘要:源碼分析四模塊上一篇我們看到,通過對命令行傳入的參數(shù)和配置文件里的配置項做了轉(zhuǎn)換包裝,然后傳遞給的模塊去編譯。這一篇我們來看看做了些什么事。在上面的分析中,我們看到最核心的其實就是實例,接下來我們就看下它的類的內(nèi)部邏輯。
webpack 源碼分析(四)——complier模塊
上一篇我們看到,webpack-cli 通過 `yargs 對命令行傳入的參數(shù)和配置文件里的配置項做了轉(zhuǎn)換包裝,然后傳遞給 webpack 的 compiler 模塊去編譯。
這一篇我們來看看 compiler 做了些什么事。
入口首先,我們來看看 webpack 是在什么地方引入 Compiler 這個模塊的,在 webpack/lib/webpack.js 中我們發(fā)現(xiàn),這個文件第一行就引入了它,并在下面的主要邏輯中使用了它:
const Compiler = require("./Compiler"); …… /* * options:這就是由 webpack-cli 轉(zhuǎn)換包裝后的配置項 * callback:第二篇分析時,發(fā)現(xiàn) `webpack-cli` 只是傳入了 options對象來獲取 `compiler` 對象,并沒有傳入回調(diào) */ const webpack = (options, callback) => { // 驗證配置項的格式 // webpackOptionsSchema 是一個json格式的描述文件,它描述了webpack可接受的所有配置項及其格式 // options 是用戶定義的webpack.config.*.js中導(dǎo)出的所有配置項 // validateSchema 使用 ajv 包,根據(jù) webpackOptionsSchema 中定義的數(shù)據(jù)類型和描述來校驗 options 中的各項配置項,最后返回一個錯誤對象,其中包含所有錯誤的配置項及說明 const webpackOptionsValidationErrors = validateSchema( webpackOptionsSchema, options ); // 如果存在配置項錯誤,則拋出所有錯誤 if (webpackOptionsValidationErrors.length) { throw new WebpackOptionsValidationError(webpackOptionsValidationErrors); } //判斷配置項是否數(shù)組,如果是數(shù)組則使用MultiCompiler進行編譯,否則使用Compiler模塊進行編譯,一般情況下,我們的 options 都是對象不是數(shù)組 let compiler; if (Array.isArray(options)) { compiler = new MultiCompiler(options.map(options => webpack(options))); } else if (typeof options === "object") { //使用默認配置項處理輸入配置項 // WebpackOptionsDefaulter 繼承自 OptionsDefaulter 類 // 在這個類里有兩個對象: // * this.defaults : 用來存放配置項的值 // * this.config : 用來存放配置項的值的類型 // process 方法的處理邏輯: // * 如果defaults對象中存在,但在config對象中不存在,并且在options中也不存在,就從 defaults對象中復(fù)制一份到options中 // * 如果在config對象中存在并且值為 “call”,則說明它的值是一個方法調(diào)用,就直接調(diào)用,并將options作為參數(shù)傳入 // * 如果在config對象中存在且值為 “make”,并且在 options中沒有,則說明它是一個方法,就直接調(diào)用它,并將options作為參數(shù)傳入,拿到返回值,賦值給options中對應(yīng)的項 // * 如果在config對象中存在切值為 “append”,則取出options中對應(yīng)的值,如果它不是數(shù)組,就把它重置為數(shù)組,并且把defaults對象中的值復(fù)制到數(shù)組中,最后將這個數(shù)組作為值賦值給options相應(yīng)的項 options = new WebpackOptionsDefaulter().process(options); // new 一個compiler實例,參數(shù)為當(dāng)前執(zhí)行node命令的目錄路徑 // Compiler類繼承自我們上一篇講過的Tapable類,在構(gòu)造函數(shù)中,初始化了各種類型的鉤子實例 // compiler 類的內(nèi)部邏輯,后面詳解++++++++++++++++++++++ compiler = new Compiler(options.context); // WebpackOptionsDefaulter類處理后返回的options 復(fù)制給 compiler compiler.options = options; // 使用NodeEnviromentPlugin 類給compiler添加文件輸入輸出的能力 // NodeEnviromentPlugin的內(nèi)部邏輯,后面詳解++++++++++++++++++++++++++ new NodeEnvironmentPlugin().apply(compiler); // 如果配置項中有插件配置并且插件配置為數(shù)組 // 遍歷插件數(shù)組,如果插件是一個函數(shù),則使用complier來調(diào)用它,,并且將compier作為參數(shù)出入 // 否則,使用 WebpackPluginInstance 的 apply 方法來返回一個 void 值(相當(dāng)于undefined) if (options.plugins && Array.isArray(options.plugins)) { for (const plugin of options.plugins) { if (typeof plugin === "function") { plugin.call(compiler, compiler); } else { plugin.apply(compiler); } } } // 觸發(fā) environment 同步鉤子,這里的 call() 是我們講過的Tapable鉤子事件的觸發(fā)方法 // environment 準(zhǔn)備好之后,執(zhí)行插件 compiler.hooks.environment.call(); // 觸發(fā) afterEnvironment 同步鉤子 // environment 安裝完成之后,執(zhí)行插件 compiler.hooks.afterEnvironment.call(); // 使用 WebpackOptionsApply 類處理選項,返回處理過的選項對象 // WebpackOptionsApply 的處理邏輯,后面詳解++++++++++++++ compiler.options = new WebpackOptionsApply().process(options, compiler); } else { //如果配置既不是數(shù)組類型也不是對象類型,拋出錯誤 throw new Error("Invalid argument: options"); } // 如果傳入了回到函數(shù) if (callback) { // 如果回調(diào)不是函數(shù),拋出參數(shù)類型錯誤 if (typeof callback !== "function") { throw new Error("Invalid argument: callback"); } // 如果是監(jiān)聽模式,或者(配置是數(shù)組且數(shù)組中的項中有監(jiān)聽選項為true),則初始化監(jiān)聽配置,最后返回compiler實例的監(jiān)聽方法 // 實例的監(jiān)聽方法會返回一個 Watching類的實例,它本質(zhì)上是一個觀察者 if ( options.watch === true || (Array.isArray(options) && options.some(o => o.watch)) ) { const watchOptions = Array.isArray(options) ? options.map(o => o.watchOptions || {}) : options.watchOptions || {}; return compiler.watch(watchOptions, callback); } // 使用compiler的run方法運行回調(diào) compiler.run(callback); } //返回compiler實例 return compiler; };
通過以上源碼分析,我們得知,在 webpack() 中,實際上總共做了三件事:
對參數(shù)進行校驗和規(guī)范化處理;
new 一個編譯器實例并且初始化各種tapable鉤子,并且在環(huán)境準(zhǔn)備好和安裝完成后執(zhí)行響應(yīng)的鉤子
初始化監(jiān)聽。
在上面的分析中,我們看到最核心的其實就是compiler實例,接下來我們就看下它的類的內(nèi)部邏輯。
compiler 分析 主體結(jié)構(gòu)首先,我們來看主要結(jié)構(gòu):
/*…… *// 各種引入 // Compiler 類繼承自Tapable class Compiler extends Tapable { constructor(context) {……}//構(gòu)造函數(shù)執(zhí)行各種初始化操作 watch(watchOptions, handler) {……}//監(jiān)聽初始化 run(callback) {……}// 運行編譯 runAsChild(callback) {...} // 作為子編譯進程運行 purgeInputFileSystem() {...} // 凈化輸入 emitAssets(compilation, callback) {...} // 發(fā)布資源 emitRecords(callback) {...} // 發(fā)布記錄 readRecords(callback) {...} // 讀取記錄 createChildCompiler( compilation, compilerName, compilerIndex, outputOptions, plugins ) {...} // 創(chuàng)建子編譯器 isChild() {return !!this.parentCompilation;} // 是否子匯編 createCompilation() {return new Compilation(this);} // 創(chuàng)建匯編實例 newCompilation(params) {return compilation;} // 根據(jù)參數(shù)創(chuàng)建新的匯編實例 createNormalModuleFactory() {return normalModuleFactory;} // 創(chuàng)建普通模塊的工廠 createContextModuleFactory() {return contextModuleFactory;} // 創(chuàng)建上下文模塊的工廠 newCompilationParams() {return params;} // 獲取一個新的匯編參數(shù)對象 compile(callback) {} // 編譯 } module.exports = Compiler; class SizeOnlySource extends Source {} // 定義了一個類,作用是+++++++++++
下一講,我們將逐個攻破
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/110319.html
摘要:基本配置項基本配置項。的插件架構(gòu)主要基于實現(xiàn)的,這個就是專注于事件的廣播和操作。開啟多進程,加快打包速度。 這次我們主要研究的是webpack框架的相關(guān)知識,webpack是一個打包構(gòu)建的前端框架,用于解決前端開發(fā)的模塊化問題。 應(yīng)用場景和縱向比較 說到webpack,肯定你還會想到gulp和grunt這些框架,那么webpack是做什么的呢?他和其他的框架有什么區(qū)別呢?我們一起來分析...
摘要:不直接使用的原因很簡單首先構(gòu)建一次實在太慢了,特別是有幾十個頁面存在的情況下,另一個原因是我只是想拿到資源依賴,我根本不想對整個前端進行一次構(gòu)建,也不想生成任何。這就達到了本文題目中目的,用十分之一的構(gòu)建時間做一場頁面靜態(tài)資源依賴分析。原文鏈接 作者:梯田 前言: 所謂【靜態(tài)資源依賴分析】,指的是可以通過分析頁面資源后,可以以 json 數(shù)據(jù)或者圖表的方式拿到頁面資源間的依賴關(guān)系。 比如 c...
摘要:類定義了方法,用于注冊插件,將插件及其回調(diào)函數(shù)以的形式保存在內(nèi)部對象中又定義了,等方法來觸發(fā)插件的回調(diào)函數(shù)。所以當(dāng)類繼承類后,也同樣具有注冊插件和觸發(fā)回調(diào)函數(shù)的功能。 說起webpack,相信對于前端工程師們而言早已經(jīng)不是什么新鮮的事物。但是由于webpack有著較為復(fù)雜和靈活的配置項,所以給人的第一感覺是難以完全掌握。 這次就跟大家分享一下有關(guān)webpack構(gòu)建過程的相關(guān)知識,希望對...
摘要:以為例,編寫來幫助我們完成重復(fù)的工作編譯壓縮我只要執(zhí)行一下就可以檢測到文件的變化,然后為你執(zhí)行一系列的自動化操作,同樣的操作也發(fā)生在這些的預(yù)處理器上。的使用是針對第三方類庫使用各種模塊化寫法以及語法。 showImg(https://segmentfault.com/img/bVbtZYK); 一:前端工程化的發(fā)展 很久以前,互聯(lián)網(wǎng)行業(yè)有個職位叫做 軟件開發(fā)工程師 在那個時代,大家可能...
摘要:需要得到最后一個產(chǎn)生的處理結(jié)果。這個處理結(jié)果應(yīng)該是或者被轉(zhuǎn)換為一個,代表了模塊的源碼。另外還可以傳遞一個可選的結(jié)果格式為對象。在異步模式中,必須調(diào)用,來指示等待異步結(jié)果,它會返回回調(diào)函數(shù),隨后必須返回并且調(diào)用該回調(diào)函數(shù)。 準(zhǔn)備工作 安裝 Node.js, 建議安裝LTS長期支持版本 mkdir webpack and cd webpack and npm init -y npm ...
閱讀 828·2023-04-25 19:40
閱讀 3488·2023-04-25 17:41
閱讀 3002·2021-11-11 11:01
閱讀 2612·2019-08-30 15:55
閱讀 3227·2019-08-30 15:44
閱讀 1357·2019-08-29 14:07
閱讀 484·2019-08-29 11:23
閱讀 1326·2019-08-27 10:54