<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          了解 JavaScript 模塊系統(tǒng)基礎(chǔ)知識(shí),搭建自己的庫(kù)

          共 5731字,需瀏覽 12分鐘

           ·

          2020-10-17 03:16

          我想很多“前端工程師”都聽(tīng)過(guò)說(shuō)過(guò) “JavaScript 模塊”,那你們都知道如何處理它,以及它在日常工作中如何發(fā)揮作用嗎?

          JS 模塊系統(tǒng)到底是什么呢

          隨著 JavaScript 開(kāi)發(fā)越來(lái)越廣泛,命名空間和依賴(lài)項(xiàng)變得越來(lái)越難以處理,極客們?cè)缫呀?jīng)開(kāi)發(fā)出不同的模塊系統(tǒng)解決方案來(lái)解決該問(wèn)題。

          為什么理解 JS 模塊系統(tǒng)很重要

          我的日常工作是設(shè)計(jì)和項(xiàng)目架構(gòu),并且我很快意識(shí)到跨項(xiàng)目需要許多通用功能。我總是一次又一次地將這些功能復(fù)制粘貼到新項(xiàng)目中。

          問(wèn)題是,每當(dāng)更改一部分代碼時(shí),我都需要在所有項(xiàng)目中手動(dòng)同步這些更改。為了避免所有這些繁瑣的手動(dòng)任務(wù),我決定提取通用功能并從中組成一個(gè) NPM 軟件包。這樣,團(tuán)隊(duì)中的其他人將能夠?qū)⑺鼈冎匦掠米饕蕾?lài)項(xiàng),并在每次推出新版本時(shí)都可以對(duì)其進(jìn)行更新。

          這種方法具有一些優(yōu)點(diǎn):

          • 如果核心庫(kù)中有一些更改,則只需在一個(gè)地方進(jìn)行更改,而無(wú)需為同一件事重構(gòu)所有應(yīng)用程序的代碼。
          • 所有應(yīng)用程序保持同步。無(wú)論何時(shí)進(jìn)行更改,所有應(yīng)用程序僅需要運(yùn)行 npm update ?命令。

          庫(kù)的源碼

          因此,下一步是發(fā)布庫(kù)

          這是最困難的部分,因?yàn)槲夷X海中突然跳出一堆東西,例如:

          1. 如何使用搖樹(shù)優(yōu)化
          2. 應(yīng)該針對(duì)哪些 JS 模塊系統(tǒng)(CommonJS、AMD、ES modules)
          3. 需要轉(zhuǎn)譯源碼嗎
          4. 需要打包源碼嗎
          5. 應(yīng)該發(fā)布哪些文件

          在發(fā)布第三方庫(kù)(組件庫(kù),工具庫(kù))時(shí),我們每個(gè)人的腦海中都應(yīng)該冒出這些問(wèn)題。

          來(lái), 我們一步步解決以上的問(wèn)題。

          不同類(lèi)型的 JS 模塊系統(tǒng)

          1. CommonJS

          • 由?Node.js 實(shí)現(xiàn)
          • 多用在服務(wù)器端安裝模塊時(shí)
          • 沒(méi)有 runtime/async 模塊
          • 通過(guò) require ?導(dǎo)入模塊
          • 通過(guò) module.exports ?導(dǎo)出模塊
          • 無(wú)法使用搖樹(shù)優(yōu)化,因?yàn)楫?dāng)你導(dǎo)入時(shí)會(huì)得到一個(gè)模塊時(shí),得到的是一個(gè)對(duì)象,所以屬性查找在運(yùn)行時(shí)進(jìn)行,無(wú)法靜態(tài)分析
          • 會(huì)得到一個(gè)對(duì)象的副本,因此模塊本身不會(huì)實(shí)時(shí)更改
          • 循環(huán)依賴(lài)的不能優(yōu)雅處理
          • 語(yǔ)法簡(jiǎn)單

          2. AMD 異步模塊定義

          • 由 ?RequireJs ?實(shí)現(xiàn)
          • 當(dāng)你在客戶端(瀏覽器)環(huán)境中,異步加載模塊時(shí)使用
          • 通過(guò) require ?實(shí)現(xiàn)導(dǎo)入
          • 語(yǔ)法復(fù)雜

          3. UMD 通用模塊定義

          • CommonJs + AMD ?的組合(即 CommonJs 的語(yǔ)法 + AMD 的異步加載)
          • 可以用于 AMD/CommonJs 環(huán)境。
          • UMD 還支持全局變量定義,因此,UMD 模塊能夠在客戶端和服務(wù)器上工作。

          4. ES modules

          • 用于服務(wù)器/客戶端
          • 支持模塊的 Runtime/static loading
          • 當(dāng)你導(dǎo)入時(shí),獲得是實(shí)際對(duì)象
          • 通過(guò) import ?導(dǎo)入,通過(guò) export ?導(dǎo)出
          • 靜態(tài)分析——你可以決定編譯時(shí)的導(dǎo)入和導(dǎo)出(靜態(tài)),你只需要看源碼,不需要執(zhí)行它
          • 由于 ES6 支持靜態(tài)分析,因此搖樹(shù)優(yōu)化是可行的
          • 始終獲取實(shí)際值,以便實(shí)時(shí)更改模塊本身
          • 比 CommonJS 有更好的循環(huán)依賴(lài)管理

          現(xiàn)在,我們了解了不同類(lèi)型的 JS 模塊系統(tǒng)以及它們?nèi)绾窝葑儭?/p>

          盡管所有工具和現(xiàn)代瀏覽器都支持?ES modules,但我們?cè)诎l(fā)布庫(kù)時(shí)不知道用戶如何利用我們的庫(kù)。因此,我們必須確保我們的庫(kù)在所有環(huán)境中都能正常工作。

          讓我們深入研究并設(shè)計(jì)一個(gè)示例庫(kù),更好地回答與發(fā)布庫(kù)有關(guān)的所有問(wèn)題。

          我已經(jīng)建立了一個(gè)小型的 UI 庫(kù)(你可以在?GitHub 上找到源代碼),并且我將分享我在編譯,打包和發(fā)布中的所有經(jīng)驗(yàn)和探索。

          目錄結(jié)構(gòu)

          在這里,我們有一個(gè)小的 UI 庫(kù),其中包含 3 個(gè)組件:Button,Card 和 NavBar。讓我們一步步進(jìn)行編譯并發(fā)布。

          發(fā)布前的最佳實(shí)踐

          1. 搖樹(shù)優(yōu)化(Tree Shaking)

          webpack 官方文檔有說(shuō)明

          • 搖樹(shù)優(yōu)化是一個(gè)術(shù)語(yǔ),通常用于描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴(lài)于 ES2015 模塊系統(tǒng)中的靜態(tài)結(jié)構(gòu)特性,例如 [import][4] ?和 [export][5]。這個(gè)術(shù)語(yǔ)和概念實(shí)際上是興起于 ES2015 模塊打包工具 rollup。新的 webpack 4 正式版本,擴(kuò)展了這個(gè)檢測(cè)能力,通過(guò) package.json ?的 "sideEffects" ?屬性作為標(biāo)記,向 compiler 提供提示,表明項(xiàng)目中的哪些文件是純的 ES2015 模塊,由此可以安全地刪除文件中未使用的部分。
          • webpack 和 Rollup 都支持搖樹(shù)優(yōu)化,這意味著我們需要牢記某些事情,以便我們的代碼可被 Tree Shaking。

          2. 發(fā)布所有模塊形態(tài)

          • 我們應(yīng)該發(fā)布所有模塊形態(tài),例如 UMD 和?ES Module,因?yàn)槲覀冇肋h(yuǎn)不知道用戶在哪個(gè)版本的瀏覽器或 webpack 中使用此庫(kù)/包。
          • 即使所有打包程序(如 ?webpack ?和 ?Rollup)都能解析 ES Module ,但如果我們的使用者使用的是 webpack 1.x,則它無(wú)法解析 ES 模塊。
          //?package.json
          {
          ??"name":?"js-module-system",
          ??"version":?"0.0.1",


          • package.json 文件的 main 字段通常用于指向?UMD 版本的庫(kù)/包。
          • package.jso 文件的 module?字段用于指向?ES?版本的庫(kù)/包。

          鮮為人知的事實(shí):webpack 使用 resolve.mainfields 確定檢查 package.json ?中的哪些字段。

          性能提示:由于所有現(xiàn)代瀏覽器現(xiàn)在都支持 ES 模塊,因此也請(qǐng)務(wù)必發(fā)布 ?ES 版本的庫(kù)/包。這樣一來(lái),可以減少編譯次數(shù),最終可以減少向用戶交付的代碼。這將提高應(yīng)用程序的性能。

          那么,下一步是什么?編譯還是打包?我們應(yīng)該使用什么工具?啊,這是最棘手的部分!讓我們深入研究研究。

          webpack vs Rollup vs Babel

          這些我們?cè)谌粘9ぷ髦惺褂玫墓ぞ撸糜诔休d我們的應(yīng)用程序/庫(kù)/軟件包。沒(méi)有它們,我無(wú)法想象現(xiàn)代的 Web 開(kāi)發(fā)有多么糟糕。因此,我們無(wú)法將它們進(jìn)行比較 ?

          每種工具都有其自身的優(yōu)勢(shì),并根據(jù)使用者的需求達(dá)到不同的目的。

          現(xiàn)在讓我們看一下這些工具:

          webpack

          webpack?是一個(gè)很棒的模塊打包工具, 它被廣泛接受并且主要用于構(gòu)建 SPA。它提供了開(kāi)箱即用的所有功能,例如代碼拆分按需加載搖樹(shù)優(yōu)化等,并且它本身使用的是 CommonJS 模塊系統(tǒng)。

          RollupJS

          RollupJS 還是類(lèi)似于 webpack 的模塊打包器。但是,RollupJS 的主要優(yōu)點(diǎn)是它遵循 ES6 修訂版中包含的代碼模塊的新標(biāo)準(zhǔn)化格式,因此你可以使用它來(lái)打包??ES module variant 的 library/package,但它不支持按需加載

          Babel

          Babel 是 JavaScript 的編譯器,以將 ES6 代碼轉(zhuǎn)換為可在你的瀏覽器(或服務(wù)器)中運(yùn)行的代碼而聞名。請(qǐng)記住,它只是編譯而不會(huì)打包你的代碼。

          我的建議:對(duì)庫(kù)使用 Rollup.js,對(duì)應(yīng)用程序使用 webpack。

          編譯(Babel-ify)源代碼還是直接打包源代碼

          在構(gòu)建我的 NPM 庫(kù)時(shí),我花費(fèi)了大量時(shí)間來(lái)試圖找出該問(wèn)題(如何編譯、如何打包)的答案。我開(kāi)始挖掘自己的 node_modules,查找所有優(yōu)秀的庫(kù)并檢查它們的構(gòu)建系統(tǒng)。

          對(duì)比 libraries/packages 構(gòu)建的輸出

          在查看了不同 libraries/packages 的構(gòu)建輸出之后,我清楚地了解了這些庫(kù)的作者在發(fā)布之前可能會(huì)想到的不同策略。以下是我的觀察。

          如你在上圖中所看到的,我已根據(jù)它們的特性將這些庫(kù)/軟件包分為兩組:

          • UI Libraries-UI 庫(kù)(styled-components, material-ui
          • Core Packages-核心包(reactreact-dom

          你可能已經(jīng)弄清楚了這兩組之間的區(qū)別。

          UI Libraries

          • 有一個(gè) dist 文件夾,該文件夾是針對(duì) ES 和 UMD/CJS 模塊系統(tǒng) 的打包和壓縮版本。
          • 有一個(gè)?lib 文件夾,用來(lái)存放被編譯后的代碼。

          Core Packages

          • 只有一個(gè)文件夾,其中包含針對(duì) CJS 或 UMD 模塊系統(tǒng)的打包和壓縮版本。

          但是,為什么 UI Libraries 和 Core Packages 的構(gòu)建輸出有所不同?

          UI Libraries

          想象一下,如果我們只是發(fā)布庫(kù)的 bundled version 將其托管在 CDN 上,我們的用戶將直接在

          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    啊91av在线 | 无限旅游团by燕惊鸿 | 无码国产精品96久久久久孕妇 | 青娱乐国产精品 | 婷婷丁香六月天 |