久久综合九色综合97婷婷-美女视频黄频a免费-精品日本一区二区三区在线观看-日韩中文无码有码免费视频-亚洲中文字幕无码专区-扒开双腿疯狂进出爽爽爽动态照片-国产乱理伦片在线观看夜-高清极品美女毛茸茸-欧美寡妇性猛交XXX-国产亚洲精品99在线播放-日韩美女毛片又爽又大毛片,99久久久无码国产精品9,国产成a人片在线观看视频下载,欧美疯狂xxxx吞精视频

有趣生活

當前位置:首頁>職場>webpack學習方法(想知道如何高效讀懂)

webpack學習方法(想知道如何高效讀懂)

發布時間:2024-01-24閱讀(15)

導讀前言我在之前寫過的文章中提到過程序的本質是基于數據結構來設計算法,也提到了程序的兩面性,但是對于大多數前端程序員來說未免太過抽象,正好我一直試圖用一種更好的....前言

我在之前寫過的文章中提到過程序的本質是基于數據結構來設計算法, 也提到了程序的兩面性, 但是對于大多數前端程序員來說未免太過抽象, 正好我一直試圖用一種更好的方式去分析代碼, 加上對 Webpack 興趣濃厚, 本著授人以魚不如授人以漁的思想, 寫再多的源碼解析, 不如告訴你如何讀懂源碼

我看過很多同學喜歡干讀, 直接從生成代碼硬讀邏輯, 干的崩牙就不提了, 我覺得這實在不是太聰明的做法, 并且讀完之后你大概率是記不住的. 而且你覺得自己讀懂了, 其實你什么也沒讀懂, 因為你沒讀懂程序背后的設計.

首先澄清下我并不是標題黨, 但是考慮到想做些知識科普, 又無奈現在你們只想看面試相關的東西, 因此作為面試官只好被自己吊打下了

webpack學習方法(想知道如何高效讀懂)(1)

正文怎么理解 "讀懂源碼"

在一些書籍中有提到過好的代碼應該是自文檔的, 什么是自文檔 ? 所謂自文檔就是代碼本身就是設計文檔, 通過閱讀代碼你能夠理解程序背后的設計思路. 要做到這點就必須從程序設計入手來構思代碼的結構和邏輯, 那什么是一個程序的結構呢?

程序的結構

任何一個程序都有自己的結構, 這種結構一定程度上受到編程范式的影響, 比如面向對象和面向過程是兩種結構, 面向過程和函數式又是兩種結構, 這里我們分析的對象主要是基于 JavaScript 開發的程序, 遵循 JavaScript 提供的結構定義, 雖然 JavaScript 具有多范式的特性, 不過大多數情況下我們認為他是面向對象的, 這和最初的基于原型的繼承方式可以說關聯很大.

因此 JavaScript 開發的程序在結構上具有面向對象的特征, 那么在 ES6 面世之后, 這種結構基本上就是由模塊來定義的, 或者說 JavaScript 程序的結構就是由模塊構成的

因此讀懂源碼的第一步就是要分析源碼即程序的結構(模塊), 那如何分析模塊呢?

模塊是數據結構和算法的載體

在 JavaScript 程序里, 一個模塊通常是指一個文件, 但是這樣定義模塊對于分析源碼來說難度很大, 所以我這里將模塊的概念進一步抽象, 你可以理解模塊是指一個或多個文件, 那如何確認一個模塊應該包含哪些文件呢 ? 主要的依據是, 模塊內的數據結構是否有關聯性, 算法是否圍繞關聯數據結構來設計. 簡單的講, 你可以從文件命名來猜測這幾個文件是否屬于相同的模塊

并不是所有程序的源碼都是可讀的, 不好的程序設計和糟糕的命名就像一本盜版或者亂寫的書, 你根本無法從中理清脈絡, 對于這種程序分析需要一些工具輔助, 后續我會看一篇講講如何去讀這種程序的源碼, 一般面向業務的程序大多數呈現這種特征.

比如在 Webpack 中代碼主要集中在 lib 目錄下

webpack學習方法(想知道如何高效讀懂)(2)

在這里我們必須先假設 Webpack 的文件命名是符合他自身設計的, 后面會提到如何去驗證這種假設, 可以看到在 lib 目錄下其實包含很多的文件夾, 這些文件夾本身就是一個模塊, 比如 runtime, 不用看就知道里面肯定是負責運行時的一些代碼, 為此我們可以來驗證下. 比如我們打開 runtime/CompatGetDefaultExportRuntimeModule.js 這個文件, 看到里面有這樣一段代碼

/** * @returns {string} runtime code */ generate() { const { runtimeTemplate } = this.compilation; const fn = RuntimeGlobals.compatGetDefaultExport; return Template.asString([ "http:// getDefaultExport function for compatibility with non-harmony modules", `${fn} = ${runtimeTemplate.basicFunction("module", [ "var getter = module && module.__esModule ?", Template.indent([ `${runtimeTemplate.returningFunction("module[default]")} :`, `${runtimeTemplate.returningFunction("module")};` ]), `${RuntimeGlobals.definePropertyGetters}(getter, { a: getter });`, "return getter;" ])};` ]); }復制代碼

看上面的注釋了么 runtime code, 然后看內容一個代碼生成的函數, 所以你基本可以篤定 runtime 文件夾下的文件主要都是負責構造運行時包裹的代碼的, 這就像你看一本書, 如果書的目錄上寫著 "xxx - xxxxx" 然后你發現這部分內容你暫時并不關心, 你就可以跳過不看. 其實這一段已經表達了我的第二個技巧, 如何看懂程序的邏輯說了這么多,如果你不想錯過web前端這么好的工具,又擔心自學遇到問題無處解決的,小編準備了一份web前端學習資料,給那些正在學習web前端的同學,或者準備學習web前端的同學,關注,轉發,私信小編“01”即可免費獲取!

webpack學習方法(想知道如何高效讀懂)(3)

程序的邏輯

當你能看懂一個程序的結構, 可以說基本把握住了程序的總體設計, 即便你不知道其中的細節, 但是你會了解這個程序大概包括哪些模塊, 這些模塊的職責分工是什么, 然后這個程序的處理流程, 能解決哪些問題, 在此基礎上你可以通過了解這些模塊的內部細節來讀懂程序的邏輯, 而程序的邏輯相當于一個程序的詳細設計. 比如上面提到的 runtime 模塊下的 CompatGetDefaultExportRuntimeModule.js 這個文件, 我們試著來讀懂這個文件的詳細設計

首先你要記住一點, 即 JavaScript 文件一般使用兩種代碼抽象方式, 函數, 看這個文件的第一行

class CompatGetDefaultExportRuntimeModule extends HelperRuntimeModule復制代碼

你就知道這是一個類, 并且繼承自 HelperRuntimModule, 其次是包含一個實例方法

generate(){}復制代碼

這個方法的入參是空的, 返回的是 {string} runtime code.

在此我們不看 generate 函數實現的代碼, 單純從這個詳細設計來看我們能獲得哪些信息

這是一個繼承自 HelperRuntimeModule 的子類, 從類名上看, 這個類主要負責兼容默認導出的運行時模塊代碼, 從 generate 的內部代碼來看也確實如此

"var getter = module && module.__esModule ?", Template.indent([ `${runtimeTemplate.returningFunction("module[default]")} :`, `${runtimeTemplate.returningFunction("module")};` ]),復制代碼

這里其實判斷了是否 esModule 然后輸出了不同的 default module 代碼.

因此讀懂代碼的邏輯并不是從內部代碼開始讀, 而是先從這個文件內類或者函數的詳細設計開始讀, 如果我要給 Webpack 源碼寫本書的話, 那上面這些內容就差不多是這樣一個章節

第 N 章 runtime 模塊Webpack 如何處理默認的 Default 代碼導出 ---- P102Webpack 在 runtime 模塊內定義了 CompatGetDefaultExportRuntimeModule 這個 HelperRuntimeModule 的子類, 通過子類的實例方法 generate 來生成具有判斷能力的運行時代碼.復制代碼

總結下, 一個程序的結構約等于一本書的目錄, 程序的邏輯約等于一本書的該目錄下的詳細內容.

對 runtime 不感興趣, 想知道面試時候的如何回答那些原理性問題?

我知道你們其實對 runtime 興趣不大, 一般面試很少會問到這個, 因此那就來一點有價值的例子, 讓我們一步一步來分析下大概率會被問到的問題, 作為一個混跡多年的面試官, 我理解大多數面試官的套路在 Webpack 上可能會問你兩樣東西, Plugin 和 Loader, 讓我們先來看看 Webpack 對于 Plugin 的設計是怎樣的

首先這里可能有個前提, 就是讀源碼之前先得把依賴摸清楚, 我在之前的文章中提到過 Webpack 內部使用的 JavaScript 解析器是 acorn, 同理對于 Plugin Webpack 也有自己的核心依賴, 那就是 tapable, 在讀 Plugin 相關的模塊之前, 我們先對 tapable 有個了解, 翻開 tapable 的 GitHub 主頁, 注意這句話

The tapable package expose many Hook classes, which can be used to create hooks for plugins.

現在你對 tapable 應該有個印象, 那就是這是一個鉤子庫, 為 plugin 提供各種鉤子, 那什么是鉤子, 別急讓我們回到 Webpack 的源碼, 現在我們知道 tapable 是 plugin 的核心依賴, 那 plugin 的模塊內一定會有 require 的代碼, 搜索下, 搜索結果不多, 不過我們需要做排除, 這里有個小技巧, 那就是看名字, 從若干搜索結果中你可以發現最符合插件相關的模塊其實就兩個文件

  • lib/Compilation.js
  • lib/Compiler.js

還記得 Webpack 官方提到的編寫插件核心要知道的概念么, Compiler, 因此基本可以篤定負責 Plugin 機制的主要就是這兩個文件了, 繼續之前的思路, 總體設計明了了, 那我們需要看看這些文件內的詳細設計, 先看 Compiler 的詳細設計…. 很長, 但是核心的代碼其實在這里

class Compiler { /** * @param {string} context the compilation path */ constructor(context) { this.hooks = Object.freeze({復制代碼

如果你仔細看 tapable 的 README, 你會發現這里的代碼和用例上的基本上是一樣的, tapable 和一般的事件管道并不相同, 他更像是為 Webpack 插件量身定制的一種事件管道, 并不是我們所熟知的發布訂閱模式

所這里面試就會有坑, 比如面試官問你 Webpack 的 Plugin 機制是咋回事, 如果你說是一種基于事件的, 那他會問具體的呢, 如果你知道 tapable 就可以講講這種 hook 模式和一般發布訂閱模式的區別, 但是如果你不了解這塊設計最好不要瞎答, 直接來個那就是個發布訂閱...涼涼

對于如此冗長復雜的詳細設計, 我是不會干啃的, 畢竟我沒有 00 后這么好的牙口, 所以這里又會有一個小技巧, 那就是當詳細設計太過細節, 太過復雜的時候, 我們要學會從用例入手, 什么是用例?

用例就是官方文檔給開發者看的文檔里關于如何使用的這部分, 比如關于 Plugin, 官網上會有這樣一段描述

Basic plugin architecture

Plugins are instantiated objects with an apply method on their prototype. This apply method is called once by the webpack compiler while installing the plugin. The apply method is given a reference to the underlying webpack compiler, which grants access to compiler callbacks. A simple plugin is structured as follows:

class HelloWorldPlugin { apply(compiler) { compiler.hooks.done.tap(Hello World Plugin, ( stats /* stats is passed as an argument when done hook is tapped. */ ) => { console.log(Hello World!); }); } } module.exports = HelloWorldPlugin; 復制代碼

然后在看看 Webpack 的入口文件 lib/webpack.js, 里面有這樣一段代碼

if (Array.isArray(options.plugins)) { for (const plugin of options.plugins) { if (typeof plugin === "function") { plugin.call(compiler, compiler); } else { plugin.apply(compiler); } } }復制代碼

傳入的這個 compiler 就是 Compiler 的實例

const compiler = new Compiler(options.context);復制代碼

結合這些分析內容, 關于 Plugin 部分可以做個問答總結

面試官: "了解 Webpack 插件的內部原理么?"

答: "Webpack 的 Plugin 機制的核心實現是 tapable, tapable 是為 Plugin 打造的一個鉤子管道, 可以允許插件觸發在 compiler 上定義的各種鉤子 (這里可能對于實際寫過插件的同學會問到一些具體的 api, 這里問的主要是核對是否有真實的插件開發經驗, 但不涉及對原理的掌握)"

對于一般面試可能止步于此, 但是對于那些經驗老道的面試官一定會繼續深挖

面試官: "那你怎么理解 compiler"

答: "compiler 通過 tapable 本身提供的 hook 機制定義了各種鉤子, 這些鉤子涵蓋了 Webpack 執行的構建的整個周期"

面試官: "官網的例子上還有關于 compilation 這個的描述, 能講講和 compiler 有什么不同么?"

這里還是需要用到上面的那套分析思路, 記得我說的 Plugin 模塊有兩個文件么, 除了 compiler.js 另一個就是 compilation.js, 如果你仔細閱讀其中的詳細設計, 你會發現 compilation 的鉤子定義主要和 module 和 chunk 處理相關

答: "compilation 通過 compiler 來創建, 內部也是基于 tapable, 不過 compilation 的鉤子主要針對是 chunk 和 module 的處理, 可以看成是兩條不同的處理管道"

大部分面試官可能會止步于此, 但是對于那些混跡江湖多年的骨灰級面試官, 接下來的問題可能就要直擊靈魂了

面試官: "哦, 那你能說說 tapable 的內部設計么?" , "你提到了 compilation 主要負責 chunk 和 module 的處理流程, 那讓我們來聊聊 chunk 和 module 相關的內容吧… 又是一套靈魂三連"

想知道如何應對骨灰級面試官的拷問? 點個贊, 我們下期見!!!

后話

本文主要提供一種閱讀源碼的思路, 其實好的源代碼本身就是一本書, 只是對于缺乏經驗的大部分初學者可能會被密密麻麻的代碼給嚇退, 另外本文中提到的回答只是一個總結...切忌照搬照抄, 想要通過面試, 你還是應該靜下心來按照我給你的思路, 仔細閱讀源碼, 你可以選擇你感興趣額部分, 盡量不要干那種從頭到尾讀, 干到崩牙的愚蠢方式, 那樣會讓你對閱讀源碼這件事徹底喪失興趣...

歡迎分享轉載→http://m.avcorse.com/read-221833.html

Copyright ? 2024 有趣生活 All Rights Reserve吉ICP備19000289號-5 TXT地圖HTML地圖XML地圖