JavaScript 模塊化的歷史進(jìn)程

作者:然后去遠(yuǎn)足
https://segmentfault.com/a/1190000023017398
引言
昨天在思否上閑逛,發(fā)現(xiàn)了一個(gè)有意思的問(wèn)題 。
因?yàn)檫@個(gè)問(wèn)題,我產(chǎn)生了寫一個(gè)系列文章的想法,試圖從站在歷史的角度上來(lái)看待編程世界中林林總總的問(wèn)題和解決方案。
目前中文網(wǎng)絡(luò)上充斥著大量互相“轉(zhuǎn)載”的內(nèi)容,基本是某一個(gè)技術(shù)問(wèn)題的解決方案(what??how?),卻不涉及為什么這么做和歷史緣由(why??when?)。比如你要搜 “JavaScript 有哪些模塊化方案?它們有什么區(qū)別?”,能得到一萬(wàn)個(gè)有用的結(jié)果;但要想知道 “為什么 JavaScript 有這么多模塊化方案?它們是誰(shuí)創(chuàng)建的?”,卻幾乎不可能。
因此,這一系列文章內(nèi)會(huì)盡可能的不涉及具體代碼,只談歷史故事。但會(huì)在文末提供包含部分代碼的參考鏈接,以供感興趣的朋友自行閱讀。
這個(gè)系列暫定為十篇文章,內(nèi)容會(huì)涉及前端、后端、編程語(yǔ)言、開(kāi)發(fā)工具、操作系統(tǒng)等等。也給自己立個(gè) Flag,在今年年底之前把整個(gè)系列寫完。如果沒(méi)完成目標(biāo)……就當(dāng)我沒(méi)說(shuō)過(guò)這句話(逃
正文
模塊化,是前端繞不過(guò)去的話題。
隨著 Node.js 和三大框架的流行,越來(lái)越多的前端開(kāi)發(fā)者們腦海中都會(huì)時(shí)常浮現(xiàn)一個(gè)問(wèn)題:
為什么 JavaScript 有這么多模塊化方案?
自從 1995 年 5 月,Brendan Eich?寫下了第一行 JavaScript 代碼起,JavaScript 已經(jīng)誕生了 25 年。
但這門語(yǔ)言早期僅僅作為輕量級(jí)的腳本語(yǔ)言,用于在 Web 上與用戶進(jìn)行少量的交互,并沒(méi)有依賴管理的概念。
隨著 AJAX 技術(shù)得以廣泛使用,Web 2.0 時(shí)代迅猛發(fā)展,瀏覽器承載了愈來(lái)愈多的內(nèi)容與邏輯,JavaScript 代碼越來(lái)越復(fù)雜,全局變量沖突、依賴管理混亂等問(wèn)題始終縈繞在前端開(kāi)發(fā)者們的心頭。此時(shí),JavaScript 亟需一種在其他語(yǔ)言中早已得到良好應(yīng)用的功能 —— 模塊化。
其實(shí),JavaScript 本身的標(biāo)準(zhǔn)化版本 ECMAScript 6.0 (ES6/ES2015) 中,已經(jīng)提供了模塊化方案,即?ES Module。但目前在 Node.js 體系下,最常見(jiàn)的方案其實(shí)是?CommonJS。再加上大家耳熟能詳?shù)?AMD、CMD、UMD,模塊化的事實(shí)標(biāo)準(zhǔn)如此之多。
那么為什么有如此之多的模塊化方案?它們又是在怎樣的背景下誕生的?為什么沒(méi)有一個(gè)方案 “千秋萬(wàn)代,一統(tǒng)江湖”?
接下來(lái),我會(huì)按照時(shí)間順序講述模塊化的發(fā)展歷程,順帶也就回答了上述幾個(gè)問(wèn)題。
萌芽初現(xiàn):從 YUI Library 和 jQuery 說(shuō)起
時(shí)間回到 2006 年 1 月,當(dāng)時(shí)還是國(guó)際互聯(lián)網(wǎng)巨頭的 Yahoo(雅虎),開(kāi)源了其內(nèi)部使用已久的組件庫(kù)?YUI Library。
YUI Library 采用了類似于 Java 命名空間的方式,來(lái)隔離各個(gè)模塊之間的變量,避免全局變量造成的沖突。其寫法類似于:
YUI.util.module.doSomthing();這種寫法無(wú)論是封裝還是調(diào)用時(shí)都十分繁瑣,而且當(dāng)時(shí)的 IDE 對(duì)于 JavaScript 來(lái)說(shuō)智能感知非常弱,開(kāi)發(fā)者很難知道他需要的某個(gè)方法存在于哪個(gè)命名空間下,經(jīng)常需要頻繁地查閱開(kāi)發(fā)手冊(cè),導(dǎo)致開(kāi)發(fā)體驗(yàn)十分不友好。
在 YUI 發(fā)布之后不久,John Resig?發(fā)布了?jQuery。當(dāng)時(shí)年僅 23 歲的他,不會(huì)知道自己這一時(shí)興起在 BarCamp 會(huì)議上寫下的代碼,將占據(jù)未來(lái)十幾年的 Web 領(lǐng)域。
jQuery?使用了一種新的組織方式,它利用了 JavaScript 的 IIFE(立即執(zhí)行函數(shù)表達(dá)式)和閉包的特性,將所依賴的外部變量傳給一個(gè)包裝了自身代碼的匿名函數(shù),在函數(shù)內(nèi)部就可以使用這些依賴,最后在函數(shù)的結(jié)尾把自身暴露給?window。這種寫法被很多后來(lái)的框架所模仿,其寫法類似于:
(function(root){
// balabala
root.jQuery = root.$ = jQuery;
})(window);這種寫法雖然靈活性大大提升,可以很方便地添加擴(kuò)展,但它并未解決根本問(wèn)題:所需依賴還是得外部提前提供,還是會(huì)增加全局變量。
從以上的嘗試中,可以歸納出 JavaScript 模塊化需要解決哪些問(wèn)題:
如何給模塊一個(gè)唯一標(biāo)識(shí)?
如何在模塊中使用依賴的外部模塊?
如何安全地(不污染模塊外代碼)包裝一個(gè)模塊?
如何優(yōu)雅地(不增加全局變量)把模塊暴漏出去?
圍繞著這些問(wèn)題,JavaScript 模塊化開(kāi)始了一段曲折的探索之路。
探索之路:CommonJS 與 Node.js 的誕生
讓我們來(lái)到 2009 年 1 月,此時(shí)距離 ES6 發(fā)布尚有 5 年的時(shí)間,但前端領(lǐng)域已經(jīng)迫切地需要一套真正意義上的模塊化方案,以解決全局變量污染和依賴管理混亂等問(wèn)題。
Mozilla 旗下的工程師?Kevin Dangoor,在工作之余,與同事們一起制訂了一套 JavaScript 模塊化的標(biāo)準(zhǔn)規(guī)范,并取名為?ServerJS。
ServerJS?最早用于服務(wù)端 JavaScript,旨在為配合自動(dòng)化測(cè)試等工作而提供模塊導(dǎo)入功能。
這里插一句題外話,其實(shí)早期 1995 年,Netsacpe(網(wǎng)景)公司就提供了有在服務(wù)端執(zhí)行 JavaScript 能力的產(chǎn)品,名為?Netscape Enterprise Server。但此時(shí)服務(wù)端能做的 JavaScript 還是基于瀏覽器來(lái)實(shí)現(xiàn)的,本身沒(méi)有脫離其自帶的 API 范圍。直到 2009 年 5 月,Node.js?誕生,賦予了其文件系統(tǒng)、I/O 流、網(wǎng)絡(luò)通信等能力,才真正意義上的成為了一門服務(wù)端編程語(yǔ)言。
2009 年年初,Ryan Dahl?產(chǎn)生了創(chuàng)造一個(gè)跨平臺(tái)編程框架的想法,想要基于 Google(谷歌)的?Chromium V8?引擎來(lái)實(shí)現(xiàn)。經(jīng)過(guò)幾個(gè)月緊張的開(kāi)發(fā)工作,在 5 月中旬,Node.js?首個(gè)預(yù)覽版本的開(kāi)發(fā)工作已全部結(jié)束。同年 8 月,歐洲 JSConf 開(kāi)發(fā)者大會(huì)上,Node.js?驚艷亮相。
但在此刻,Node.js?還沒(méi)有一款包管理工具,外部依賴依然要手動(dòng)下載到項(xiàng)目目錄內(nèi)再引用。歐洲 JSConf 大會(huì)結(jié)束后,Isaac Z. Schlueter?注意到了?Node.js,兩人一拍即合,決定開(kāi)發(fā)一款包管理工具,也就是后來(lái)大名鼎鼎的?Node Package Manager(即?npm)。
在開(kāi)發(fā)之初,擺在二人面前的第一個(gè)問(wèn)題就是,采用何種模塊化方案?。二人江目光鎖定在了幾個(gè)月前(2009 年 4 月)在華盛頓特區(qū)舉辦的美國(guó) JSConf 大會(huì)上公布的?ServerJS。此時(shí)的?ServerJS?已經(jīng)更名為?CommonJS,并重新制訂了標(biāo)準(zhǔn)規(guī)范,即Modules/1.0,展現(xiàn)了更大的野心,企圖一統(tǒng)所有編程語(yǔ)言的模塊化方案。
具體來(lái)說(shuō),Modules/1.0標(biāo)準(zhǔn)規(guī)范包含以下內(nèi)容:
模塊的標(biāo)識(shí)應(yīng)遵循一定的書寫規(guī)則。
定義全局函數(shù)?
require(dependency),通過(guò)傳入模塊標(biāo)識(shí)來(lái)引入其他依賴模塊,執(zhí)行的結(jié)果即為別的模塊暴漏出來(lái)的 API。如果被?
require?函數(shù)引入的模塊中也包含外部依賴,則依次加載這些依賴。如果引入模塊失敗,那么?
require?函數(shù)應(yīng)該拋出一個(gè)異常。模塊通過(guò)變量?
exports?來(lái)向外暴露 API,exports?只能是一個(gè)?object?對(duì)象,暴漏的 API 須作為該對(duì)象的屬性。
由于這個(gè)規(guī)范簡(jiǎn)單而直接,Node.js?和?npm?很快就決定采用這種模塊化的方案。至此,第一個(gè) JavaScript 模塊化方案正式登上了歷史舞臺(tái),成為前端開(kāi)發(fā)中必不可少的一環(huán)。
需要注意的是,CommonJS?是一系列標(biāo)準(zhǔn)規(guī)范的統(tǒng)稱,它包含了多個(gè)版本,從最早?ServerJS?時(shí)的?Modules/0.1,到更名為?CommonJS?后的?Modules/1.0,再到現(xiàn)在成為主流的?Modules/1.1。這些規(guī)范有很多具體的實(shí)現(xiàn),且不只局限于 JavaScript 這一種語(yǔ)言,只要遵循了這一規(guī)范,都可以稱之為?CommonJS。其中,Node.js?的實(shí)現(xiàn)叫做?Common Node Modules。CommonJS?的其他實(shí)現(xiàn),感興趣的朋友可以閱讀本文最下方的參考鏈接。
值得一提的是,CommonJS?雖然沒(méi)有進(jìn)入 ECMAScript 標(biāo)準(zhǔn)范圍內(nèi),但?CommonJS?項(xiàng)目組的很多成員,也都是 TC39(即制訂 ECMAScript 標(biāo)準(zhǔn)的委員會(huì)組織)的成員。這也為日后 ES6 引入模塊化特性打下了堅(jiān)實(shí)的基礎(chǔ)。
分道揚(yáng)鑣:CommonJS 歷史路口上的抉擇
在推出?Modules/1.0?規(guī)范后,CommonJS?在?Node.js?等環(huán)境下取得了很不錯(cuò)的實(shí)踐。
但此時(shí)的?CommonJS?有兩個(gè)重要問(wèn)題沒(méi)能得到解決,所以遲遲不能推廣到瀏覽器上:
由于外層沒(méi)有?
function?包裹,被導(dǎo)出的變量會(huì)暴露在全局中。在服務(wù)端?
require?一個(gè)模塊,只會(huì)有磁盤 I/O,所以同步加載機(jī)制沒(méi)什么問(wèn)題;但如果是瀏覽器加載,一是會(huì)產(chǎn)生開(kāi)銷更大的網(wǎng)絡(luò) I/O,二是天然異步,就會(huì)產(chǎn)生時(shí)序上的錯(cuò)誤。
因此,社區(qū)意識(shí)到,要想在瀏覽器環(huán)境中也能順利使用?CommonJS,勢(shì)必重新制訂新的標(biāo)準(zhǔn)規(guī)范。但新的規(guī)范怎么制訂,成為了激烈爭(zhēng)論的焦點(diǎn),分歧和沖突由此誕生,逐步形成了三大流派:
Modules/1.x?派:這派的觀點(diǎn)是,既然?Modules/1.0?已經(jīng)在服務(wù)器端有了很好的實(shí)踐經(jīng)驗(yàn),那么只需要將它移植到瀏覽器端就好。在瀏覽器加載模塊之前,先通過(guò)工具將模塊轉(zhuǎn)換成瀏覽器能運(yùn)行的代碼了。我們可以理解為他們是“保守派”。
Modules/Async?派:這派認(rèn)為,既然瀏覽器環(huán)境于服務(wù)器環(huán)境差異過(guò)大,那么就不應(yīng)該繼續(xù)在?Modules/1.0?的基礎(chǔ)上小修小補(bǔ),應(yīng)該遵循瀏覽器本身的特點(diǎn),放棄?
require?方式改為回調(diào),將同步加載模塊變?yōu)楫惒郊虞d模塊,這樣就可以通過(guò) ”下載 -> 回調(diào)“ 的方式,避免時(shí)序問(wèn)題。我們可以理解為他們是“激進(jìn)派”。Modules/2.0?派:這派同樣也認(rèn)為不應(yīng)該沿用?Modules/1.0,但也不向激進(jìn)派一樣過(guò)于激進(jìn),認(rèn)為?
require?等規(guī)范還是有可取之處,不應(yīng)該隨隨便便放棄,而是要盡可能的保持一致;但激進(jìn)派的優(yōu)點(diǎn)也應(yīng)該吸收,比如?exports?也可以導(dǎo)出其他類型、而不僅局限于?object?對(duì)象。我們可以理解為他們是“中間派”。
其中保守派的思路跟今天通過(guò)?babel?等工具,將 JavaScript 高版本代碼轉(zhuǎn)譯為低版本代碼如出一轍,主要目的就是為了兼容。有了這種想法,這派人馬提出了?Modules/Transport?規(guī)范,用于規(guī)定模塊如何轉(zhuǎn)譯。browserify?就是這一觀點(diǎn)下的產(chǎn)物。
激進(jìn)派也提出了自己的規(guī)范?Modules/AsynchronousDefinition,奈何這一派的觀點(diǎn)并沒(méi)有得到?CommonJS?社區(qū)的主流認(rèn)可。
中間派同樣也有自己的規(guī)范?Modules/Wrappings,但這派人馬最后也不了了之,沒(méi)能掀起什么風(fēng)浪。
激進(jìn)派、中間派與保守派的理念不和,最終為?CommonJS?社區(qū)分裂埋下伏筆。
百家爭(zhēng)鳴:激進(jìn)派 —— AMD 的崛起
激進(jìn)派的?James Burke?在 2009 年 9 月開(kāi)發(fā)出了?RequireJS?這一模塊加載器,以實(shí)踐證明自己的觀點(diǎn)。
但激進(jìn)派的想法始終得不到?CommonJS?社區(qū)主流認(rèn)可。雙方的分歧點(diǎn)主要在于執(zhí)行時(shí)機(jī)問(wèn)題,Modules/1.0?是延遲加載、且同一模塊只執(zhí)行一次,而?Modules/AsynchronousDefinition?卻是提前加載,加之破壞了就近聲明(就近依賴)原則,還引入了?define?等新的全局函數(shù),雙方的分歧越來(lái)越大。
最終,在?James Burke、Karl Westin?等人的帶領(lǐng)下,激進(jìn)派于同年年底宣布離開(kāi)?CommonJS?社區(qū),自立門戶。
激進(jìn)派在離開(kāi)社區(qū)后,起初專注于?RequireJS?的開(kāi)發(fā)工作,并沒(méi)有過(guò)多的涉足社區(qū)工作,也沒(méi)有此草新的標(biāo)準(zhǔn)規(guī)范。
2011 年 2 月,在?RequireJS?的擁躉們的共同努力下,由?Kris Zyp?起草的?Async Module Definition(簡(jiǎn)稱?AMD)標(biāo)準(zhǔn)規(guī)范正式發(fā)布,并在?RequireJS?社區(qū)的基礎(chǔ)上建立了?AMD?社區(qū)。
AMD?標(biāo)準(zhǔn)規(guī)范主要包含了以下幾個(gè)內(nèi)容:
模塊的標(biāo)識(shí)遵循?CommonJS Module Identifiers。
定義全局函數(shù)?
define(id, dependencies, factory),用于定義模塊。dependencies?為依賴的模塊數(shù)組,在?factory?中需傳入形參與之一一對(duì)應(yīng)。如果?
dependencies?的值中有?require、exports?或module,則與?CommonJS?中的實(shí)現(xiàn)保持一致。如果?
dependencies?省略不寫,則默認(rèn)為?['require', 'exports', 'module'],factory?中也會(huì)默認(rèn)傳入三者。如果?
factory?為函數(shù),模塊可以通過(guò)以下三種方式對(duì)外暴漏 API:return?任意類型;exports.XModule = XModule、module.exports = XModule。如果?
factory?為對(duì)象,則該對(duì)象即為模塊的導(dǎo)出值。
其中第三、四兩點(diǎn),即所謂的?Modules/Wrappings,是因?yàn)?AMD?社區(qū)對(duì)于要寫一堆回調(diào)這種做法頗有微辭,最后?RequireJS?團(tuán)隊(duì)妥協(xié),搞出這么個(gè)部分兼容支持。
因?yàn)?AMD?符合在瀏覽器端開(kāi)發(fā)的習(xí)慣方式,也是第一個(gè)支持瀏覽器端的 JavaScript 模塊化解決方案,RequireJS?迅速被廣大開(kāi)發(fā)者所接受。
但有?CommonJS?珠玉在前,很多開(kāi)發(fā)者對(duì)于要寫很多回調(diào)的方式頗有微詞。在呼吁高漲聲中,RequireJS?團(tuán)隊(duì)最終妥協(xié),搞出個(gè)?Simplified CommonJS wrapping(簡(jiǎn)稱?CJS)的兼容方式,即上文的第三、四兩點(diǎn)。但由于背后實(shí)際還是?AMD,所以只是寫法上做了兼容,實(shí)際上并沒(méi)有真正做到?CommonJS?的延遲加載。
與?CommonJS?規(guī)范有眾多實(shí)現(xiàn)不同的是,AMD?只專注于 JavaScript 語(yǔ)言,且實(shí)現(xiàn)并不多,目前只有?RequireJS?和?Dojo Toolkit,其中后者已經(jīng)停止維護(hù)。
一波三折:中間派 —— CMD 的衰落
由于?AMD?的提前加載的問(wèn)題,被很多開(kāi)發(fā)者擔(dān)心會(huì)有性能問(wèn)題而吐槽。
例如,如果一個(gè)模塊依賴了十個(gè)其他模塊,那么在本模塊的代碼執(zhí)行之前,要先把其他十個(gè)模塊的代碼都執(zhí)行一遍,不管這些模塊是不是馬上會(huì)被用到。這個(gè)性能消耗是不容忽視的。
為了避免這個(gè)問(wèn)題,上文提到,中間派試圖保留?CommonJS?書寫方式和延遲加載、就近聲明(就近依賴)等特性,并引入異步加載機(jī)制,以適配瀏覽器特性。
其中一位中間派的大佬?Wes Garland,本身是?CommonJS?的主要貢獻(xiàn)者之一,在社區(qū)中很受尊重。他在?CommonJS?的基礎(chǔ)之上,起草了?Modules/2.0,并給出了一個(gè)名為?BravoJS?的實(shí)現(xiàn)。
另一位中間派大佬?@khs4473?提出了?Modules/Wrappings,并給出了一個(gè)名為?FlyScript?的實(shí)現(xiàn)。
但?Wes Garland?本人是學(xué)院派,理論功底十分扎實(shí),但寫出的作品卻既不優(yōu)雅也不實(shí)用。而實(shí)戰(zhàn)派的?@khs4473?則在與?James Burke?發(fā)生了一些爭(zhēng)論,最后刪除了自己的 GitHub 倉(cāng)庫(kù)并停掉了?FlyScript?官網(wǎng)。
到此為止,中間一派基本已全軍覆滅,空有理論,沒(méi)有實(shí)踐。
讓我們前進(jìn)到 2011 年 4 月,國(guó)內(nèi)阿里巴巴集團(tuán)的前端大佬玉伯(本名王保平),在給?RequireJS?不斷提出建議卻被拒絕之后,萌生了自己寫一個(gè)模塊加載器的想法。
在借鑒了?CommonJS、AMD?等模塊化方案后,玉伯寫出了?SeaJS,不過(guò)這一實(shí)現(xiàn)并沒(méi)有嚴(yán)格遵守?Modules/Wrappings?的規(guī)范,所以嚴(yán)格來(lái)說(shuō)并不能稱之為?Modules/2.0。在此基礎(chǔ)上,玉伯提出了?Common Module Definition(簡(jiǎn)稱?CMD)這一標(biāo)準(zhǔn)規(guī)范。
CMD?規(guī)范的主要內(nèi)容與?AMD?大致相同,不過(guò)保留了?CommonJS?中最重要的延遲加載、就近聲明(就近依賴)特性。
隨著國(guó)內(nèi)互聯(lián)網(wǎng)公司之間的技術(shù)交流,SeaJS?在國(guó)內(nèi)得到了廣泛使用。不過(guò)在國(guó)外,也許是因?yàn)檎Z(yǔ)言障礙等原因,并沒(méi)有得到非常大范圍的推廣。
兼容并濟(jì):UMD 的統(tǒng)一
2014 年 9 月,美籍華裔?Homa Wong?提交了?UMD?第一個(gè)版本的代碼。
UMD?即?Universal Module Definition?的縮寫,它本質(zhì)上并不是一個(gè)真正的模塊化方案,而是將?CommonJS?和?AMD?相結(jié)合。
UMD?作出了如下內(nèi)容的規(guī)定:
優(yōu)先判斷是否存在?
exports?方法,如果存在,則采用?CommonJS?方式加載模塊;其次判斷是否存在?
define?方法,如果存在,則采用?AMD?方式加載模塊;最后判斷?
global?對(duì)象上是否定義了所需依賴,如果存在,則直接使用;反之,則拋出異常。
這樣一來(lái),模塊開(kāi)發(fā)者就可以使自己的模塊同時(shí)支持?CommonJS?和?AMD?的導(dǎo)出方式,而模塊使用者也無(wú)需關(guān)注自己依賴的模塊使用的是哪種方案。
姍姍來(lái)遲:欽定的 ES6/ES2015
時(shí)間前進(jìn)到 2016 年 5 月,經(jīng)過(guò)了兩年的討論,ECMAScript 6.0 終于正式通過(guò)決議,成為了國(guó)際標(biāo)準(zhǔn)。
在這一標(biāo)準(zhǔn)中,首次引入了?import?和?export?兩個(gè) JavaScript 關(guān)鍵字,并提供了被稱為?ES Module?的模塊化方案。
在 JavaScript 出生的第 21 個(gè)年頭里,JavaScript 終于迎來(lái)了屬于自己的模塊化方案。
但由于歷史上的先行者已經(jīng)占據(jù)了優(yōu)勢(shì)地位,所以?ES Module?遲遲沒(méi)有完全替換上文提到的幾種方案,甚至連瀏覽器本身都沒(méi)有立即作出支持。
2017 年 9 月上旬,Chrome?61.0 版本發(fā)布,首次在瀏覽器端原生支持了?ES Module。
2017 年 9 月中旬,Node.js?迅速跟隨,發(fā)布了 8.5.0,以支持原生模塊化,這一特性被稱之為?ECMAScript Modules(簡(jiǎn)稱?MJS)。不過(guò)到目前為止,這一特性還處于試驗(yàn)性階段。
不過(guò)隨著?babel、Webpack、TypeScript?等工具的興起,前端開(kāi)發(fā)者們已經(jīng)不再關(guān)心以上幾種方式的兼容問(wèn)題,習(xí)慣寫哪種就寫哪種,最后由工具統(tǒng)一轉(zhuǎn)譯成瀏覽器所支持的方式。
因此,預(yù)計(jì)在今后很長(zhǎng)的一段時(shí)間里,幾種模塊化方案都會(huì)在前端開(kāi)發(fā)中共存。
尾聲
本文以時(shí)間線為基準(zhǔn),從作者、社區(qū)、理念等幾個(gè)維度談到了 JavaScript 模塊化的幾大方案。
其實(shí)模塊化方案遠(yuǎn)不止提到的這些,但其他的都沒(méi)有這些流行,這里也就不費(fèi)筆墨。
文中并沒(méi)有提及各個(gè)模塊化方案是如何實(shí)現(xiàn)的,也沒(méi)有給出相關(guān)的代碼示例,感興趣的朋友可以自行閱讀下方的參考閱讀鏈接。
下面我們?cè)倏偨Y(jié)梳理一下時(shí)間線:
| 時(shí)間 | 事件 |
|---|---|
| 1995.05? ? ?? | Brendan Eich?開(kāi)發(fā) JavaScript。 |
| 2006.01 | Yahoo 開(kāi)源?YUI Library,采用命名空間方式管理模塊。 |
| 2006.01 | John Resig?開(kāi)發(fā)?jQuery,采用 IIFE + 閉包管理模塊。 |
| 2009.01 | Kevin Dangoor?起草?ServerJS,并公布第一個(gè)版本?Modules/0.1。 |
| 2009.04 | Kevin Dangoor?在美國(guó) JSConf 公布?CommonJS。 |
| 2009.05 | Ryan Dahl?開(kāi)發(fā)?Node.js。 |
| 2009.08 | Ryan Dahl?在歐洲 JSConf 公布?Node.js。 |
| 2009.08 | Kevin Dangoor?將?ServerJS?改名為?CommonJS,并起草第二個(gè)版本?Modules/1.0。 |
| 2009.09 | James Burke?開(kāi)發(fā)?RequireJS。 |
| 2010.01 | Isaac Z. Schlueter?開(kāi)發(fā)?npm,實(shí)現(xiàn)了基于?CommonJS?模塊化方案的?Common Node Modules。 |
| 2010.02 | Kris Zyp?起草?AMD,AMD/RequireJS?社區(qū)成立。 |
| 2011.01 | 玉伯開(kāi)發(fā)?SeaJS,起草?CMD,CMD/SeaJS?社區(qū)成立。 |
| 2014.08 | Homa Wong?開(kāi)發(fā)?UMD。 |
| 2015.05 | ES6 發(fā)布,新增特性?ES Module。 |
| 2017.09 | Chrome?和?Node.js?開(kāi)始原生支持?ES Module。 |
注:文章中的所有人物、事件、時(shí)間、地點(diǎn),均來(lái)自于互聯(lián)網(wǎng)公開(kāi)內(nèi)容,由本人進(jìn)行搜集整理,其中如有謬誤之處,還請(qǐng)多多指教。
參考閱讀
《Wikipedia - YUI Library》
《Wikipedia - jQuery》
《Wikipedia - List of server-side JavaScript implementations》
《Wikipedia - CommonJS》
《Wikipedia - Asynchronous Module Definition》
《CommonJS Project History》
《RequireJS Project History》
《JavaScript Modules: A Brief History》
《淺析 JS 模塊規(guī)范:AMD,CMD,CommonJS》
《JavaScript Module Loader - CommonJS,RequireJS,SeaJS 歸納筆記》
《前端模塊化開(kāi)發(fā)那點(diǎn)歷史》
分享前端好文,點(diǎn)亮?在看?

