模塊系統(tǒng)的演變

首先掌实,模塊系統(tǒng)主要解決模塊的定義蓖议,依賴和導(dǎo)出,先看看已經(jīng)存在的模塊系統(tǒng)琼掠。

1:<script>標(biāo)簽

<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>

這是最原始的 JavaScript 文件加載方式,如果把每一個(gè)文件看做是一個(gè)模塊停撞,那么他們的接口通常是暴露在全局作用域下眉枕,也就是定義在 window
對(duì)象中,不同模塊的接口調(diào)用都是一個(gè)作用域中怜森,一些復(fù)雜的框架速挑,會(huì)使用命名空間的概念來(lái)組織這些模塊的接口,典型的例子如 YUI 庫(kù)副硅。

這種原始的加載方式暴露了一些顯而易見(jiàn)的弊端:

  • 全局作用域下容易造成變量沖突+
  • 文件只能按照 <script> 的書(shū)寫順序進(jìn)行加載
  • 開(kāi)發(fā)人員必須主觀解決模塊和代碼庫(kù)的依賴關(guān)系
  • 在大型項(xiàng)目中各種資源難以管理姥宝,長(zhǎng)期積累的問(wèn)題導(dǎo)致代碼庫(kù)混亂不堪

2:CommonJS

服務(wù)器端的 Node.js 遵循 CommonJS規(guī)范,該規(guī)范的核心思想是允許模塊通過(guò) require方法來(lái)同步加載所要依賴的其他模塊恐疲,然后通過(guò) exports或 module.exports來(lái)導(dǎo)出需要暴露的接口腊满。

require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

優(yōu)點(diǎn):

  • 服務(wù)器端模塊便于重用
  • NPM 中已經(jīng)有將近20萬(wàn)個(gè)可以使用模塊包
  • 簡(jiǎn)單并容易使用

缺點(diǎn):

  • 同步的模塊加載方式不適合在瀏覽器環(huán)境中套么,同步意味著阻塞加載,瀏覽器資源是異步加載的
  • 不能非阻塞的并行加載多個(gè)模塊

實(shí)現(xiàn):

  • 服務(wù)器端的 Node.js
  • Browserify碳蛋,瀏覽器端的 CommonJS 實(shí)現(xiàn)胚泌,可以使用 NPM 的模塊,但是編譯打包后的文件體積可能很大
  • modules-webmake肃弟,類似Browserify玷室,還不如 Browserify 靈活
  • wreq,Browserify 的前身

3:AMD

Asynchronous Module Definition 規(guī)范其實(shí)只有一個(gè)主要口 define(id?, dependencies?, factory)笤受,它要在聲明模塊的時(shí)候指定所有的依賴 dependencies穷缤,并且還要當(dāng)做形參傳到 factory中,對(duì)于依賴的模塊提前執(zhí)行箩兽,依賴前置津肛。

define("module", ["dep1", "dep2"], function(d1, d2) {
  return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });

優(yōu)點(diǎn):

  • 適合在瀏覽器環(huán)境中異步加載模塊
  • 可以并行加載多個(gè)模塊

缺點(diǎn):

  • 提高了開(kāi)發(fā)成本,代碼的閱讀和書(shū)寫比較困難汗贫,模塊定義方式的語(yǔ)義不順暢
  • 不符合通用的模塊化思維方式身坐,是一種妥協(xié)的實(shí)現(xiàn)

實(shí)現(xiàn):

4:CMD

Common Module Definition 規(guī)范和 AMD 很相似,盡量保持簡(jiǎn)單落包,并與 CommonJS 和 Node.js 的 Modules 規(guī)范保持了很大的兼容性掀亥。

define(function(require, exports, module) {
  var $ = require('jquery');
  var Spinning = require('./spinning');
  exports.doSomething = ...
  module.exports = ...
})

優(yōu)點(diǎn):

  • 依賴就近,延遲執(zhí)行
  • 可以很容易在 Node.js 中運(yùn)行

缺點(diǎn):

  • 依賴 SPM 打包妥色,模塊的加載邏輯偏重

實(shí)現(xiàn):

5:UMD

Universal Module Definition 規(guī)范類似于兼容 CommonJS 和 AMD 的語(yǔ)法糖,是模塊定義的跨平臺(tái)解決方案遏片。

6:ES6 模塊

EcmaScript6 標(biāo)準(zhǔn)增加了 JavaScript 語(yǔ)言層面的模塊體系定義嘹害。ES6 模塊的設(shè)計(jì)思想,是盡量的靜態(tài)化吮便,使得編譯時(shí)就能確定模塊的依賴關(guān)系笔呀,以及輸入和輸出的變量。CommonJS 和 AMD 模塊髓需,都只能在運(yùn)行時(shí)確定這些東西许师。
優(yōu)點(diǎn):

  • 容易進(jìn)行靜態(tài)分析
  • 面向未來(lái)的 EcmaScript 標(biāo)準(zhǔn)

缺點(diǎn):

  • 原生瀏覽器端還沒(méi)有實(shí)現(xiàn)該標(biāo)準(zhǔn)
  • 全新的命令字,新版的 Node.js才支持

實(shí)現(xiàn):

7:前端模塊加載

前端模塊要在客戶端中執(zhí)行僚匆,所以他們需要增量加載到瀏覽器中微渠。

模塊的加載和傳輸,我們首先能想到兩種極端的方式咧擂,一種是每個(gè)模塊文件都單獨(dú)請(qǐng)求逞盆,另一種是把所有模塊打包成一個(gè)文件然后只請(qǐng)求一次。顯而易見(jiàn)松申,每個(gè)模塊都發(fā)起單獨(dú)的請(qǐng)求造成了請(qǐng)求次數(shù)過(guò)多云芦,導(dǎo)致應(yīng)用啟動(dòng)速度慢俯逾;一次請(qǐng)求加載所有模塊導(dǎo)致流量浪費(fèi)、初始化過(guò)程慢舅逸。這兩種方式都不是好的解決方案桌肴,它們過(guò)于簡(jiǎn)單粗暴。

分塊傳輸琉历,按需進(jìn)行懶加載坠七,在實(shí)際用到某些模塊的時(shí)候再增量更新,才是較為合理的模塊加載方案善已。

要實(shí)現(xiàn)模塊的按需加載灼捂,就需要一個(gè)對(duì)整個(gè)代碼庫(kù)中的模塊進(jìn)行靜態(tài)分析、編譯打包的過(guò)程换团。

8:所有資源都是模塊

在上面的分析過(guò)程中悉稠,我們提到的模塊僅僅是指JavaScript模塊文件。然而艘包,在前端開(kāi)發(fā)過(guò)程中還涉及到樣式的猛、圖片、字體想虎、HTML 模板等等眾多的資源卦尊。這些資源還會(huì)以各種方言的形式存在,比如 coffeescript舌厨、 less岂却、 sass、眾多的模板庫(kù)裙椭、多語(yǔ)言系統(tǒng)(i18n)等等躏哩。

如果他們都可以視作模塊,并且都可以通過(guò)require的方式來(lái)加載揉燃,將帶來(lái)優(yōu)雅的開(kāi)發(fā)體驗(yàn)扫尺,比如:

require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");

那么如何做到讓 require 能加載各種資源呢?

9:靜態(tài)分析

在編譯的時(shí)候炊汤,要對(duì)整個(gè)代碼進(jìn)行靜態(tài)分析正驻,分析出各個(gè)模塊的類型和它們依賴關(guān)系,然后將不同類型的模塊提交給適配的加載器來(lái)處理抢腐。比如一個(gè)用 LESS 寫的樣式模塊姑曙,可以先用 LESS 加載器將它轉(zhuǎn)成一個(gè)CSS 模塊,在通過(guò) CSS 模塊把他插入到頁(yè)面的 <style> 標(biāo)簽中執(zhí)行迈倍。Webpack 就是在這樣的需求中應(yīng)運(yùn)而生渣磷。

同時(shí),為了能利用已經(jīng)存在的各種框架授瘦、庫(kù)和已經(jīng)寫好的文件醋界,我們還需要一個(gè)模塊加載的兼容策略竟宋,來(lái)避免重寫所有的模塊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末形纺,一起剝皮案震驚了整個(gè)濱河市丘侠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逐样,老刑警劉巖蜗字,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異脂新,居然都是意外死亡挪捕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門争便,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)级零,“玉大人,你說(shuō)我怎么就攤上這事滞乙∽嗉停” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵斩启,是天一觀的道長(zhǎng)序调。 經(jīng)常有香客問(wèn)我,道長(zhǎng)兔簇,這世上最難降的妖魔是什么发绢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮垄琐,結(jié)果婚禮上边酒,老公的妹妹穿的比我還像新娘。我一直安慰自己此虑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布口锭。 她就那樣靜靜地躺著朦前,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹃操。 梳的紋絲不亂的頭發(fā)上韭寸,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天,我揣著相機(jī)與錄音荆隘,去河邊找鬼恩伺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛椰拒,可吹牛的內(nèi)容都是我干的晶渠。 我是一名探鬼主播凰荚,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼褒脯!你這毒婦竟也來(lái)了便瑟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤番川,失蹤者是張志新(化名)和其女友劉穎到涂,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體颁督,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡践啄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沉御。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屿讽。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嚷节,靈堂內(nèi)的尸體忽然破棺而出聂儒,到底是詐尸還是另有隱情,我是刑警寧澤硫痰,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布衩婚,位于F島的核電站,受9級(jí)特大地震影響效斑,放射性物質(zhì)發(fā)生泄漏非春。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一缓屠、第九天 我趴在偏房一處隱蔽的房頂上張望奇昙。 院中可真熱鬧,春花似錦敌完、人聲如沸储耐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)什湘。三九已至,卻和暖如春晦攒,著一層夾襖步出監(jiān)牢的瞬間闽撤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工脯颜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哟旗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像闸餐,于是被迫代替她去往敵國(guó)和親饱亮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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

  • JS中的模塊規(guī)范(CommonJS,AMD场勤,CMD)戈锻,如果你聽(tīng)過(guò)js模塊化這個(gè)東西,那么你就應(yīng)該聽(tīng)過(guò)或Common...
    小蝦米前端閱讀 4,384評(píng)論 0 12
  • 寫在開(kāi)頭 先說(shuō)說(shuō)為什么要寫這篇文章, 最初的原因是組里的小朋友們看了webpack文檔后, 表情都是這樣的: (摘...
    Lefter閱讀 5,273評(píng)論 4 31
  • 原文鏈接:https://auth0.com/blog/javascript-module-systems-sho...
    自度君閱讀 910評(píng)論 0 2
  • 1 Node.js模塊的實(shí)現(xiàn) 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都著...
    zlx_2017閱讀 1,218評(píng)論 0 1
  • 畢業(yè)之后就很少做綠皮火車了和媳,大抵是因?yàn)檫@個(gè)交通工具太過(guò)耗費(fèi)時(shí)間格遭,飛機(jī)兩三個(gè)小時(shí)可以到達(dá)的,它要一兩天留瞳,高鐵一兩個(gè)小...
    如此青梨閱讀 702評(píng)論 0 0