AMD、CMD、CommonJS、UMD、ESM
隨著前端發展的不斷進步,JavaScript的模組化不僅在NodeJS中應用,也被拿到了瀏覽器上得到應用,所以出現了一些模組化的規範
AMD(Asynchromous Module Definition - 非同步模組定義)
AMD是RequireJS在推廣過程中對模組定義的規範化產出,AMD是非同步載入模組,推崇依賴前置。
define('module1', ['jquery'], ($) => { //do something... });
程式碼中依賴被前置,當定義模組(module1)時,就會載入依賴(jquery)
CMD(Common Module Definition - 公共模組定義)
CMD是SeaJS在推廣過程中對模組定義的規範化產出,對於模組的依賴,CMD是延遲執行,推崇依賴就近。
define((require, exports, module) => { module.exports = { fun1: () => { var $ = require('jquery'); return $('#test'); } }; });
如上程式碼,只有當真正執行到fun1方法時,才回去執行jquery。
同時CMD也是延自CommonJS Modules/2.0規範
CommonJS
提到CMD,就不得不提起CommonJS,CommonJS是服務端模組的規範,由於Node.js被廣泛認知。
根據CommonJS規範,一個單獨的檔案就是一個模組。載入模組使用require方法,該方法讀取一個檔案並執行,最後返回檔案內部的module.exports物件。
//file1.js moudle.exports = { a: 1 }; //file2.js var f1 = require('./file1'); var v = f1.a + 2; module.exports ={ v: v };
CommonJS 載入模組是同步的,所以只有載入完成才能執行後面的操作。像Node.js主要用於伺服器的程式設計,載入的模組檔案一般都已經存在本地硬碟,所以載入起來比較快,不用考慮非同步載入的方式,所以CommonJS規範比較適用。但如果是瀏覽器環境,要從伺服器載入模組,這是就必須採用非同步模式。所以就有了 AMD CMD 解決方案。
UMD(Universal Module Definition - 通用模組定義)
UMD又是個什麼玩意呢?UMD是AMD和CommonJS的一個糅合。AMD是瀏覽器優先,非同步載入;CommonJS是伺服器優先,同步載入。
既然要通用,怎麼辦呢?那就先判斷是否支援node.js的模組,存在就使用node.js;再判斷是否支援AMD(define是否存在),存在則使用AMD的方式載入。這就是所謂的UMD。
((root, factory) => { if (typeof define === 'function' && define.amd) { //AMD define(['jquery'], factory); } else if (typeof exports === 'object') { //CommonJS var $ = requie('jquery'); module.exports = factory($); } else { //都不是,瀏覽器全域性定義 root.testModule = factory(root.jQuery); } })(this, ($) => { //do something... 這裡是真正的函式體 });
ESM(ECMA Script 2015 Module)
ESM是ES6中的模組化規範,在nodeJS新版本中可以直接使用,現在大部分瀏覽器也開始支援(在script標籤上設定type="module"),
ES6 在語言標準的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代現有的 CommonJS 和 AMD 規範,成為瀏覽器和伺服器通用的模組解決方案。
// 寫法一 export var m = 1; // 寫法二 var m = 1; export { m }; // 寫法三 var n = 1; export { n as m }; // 寫法四 var n = 1; export default n; // 寫法五 if (true) { import('./myModule.js').then(({ export1, export2 }) => { /* ... */ }); } // 寫法六 Promise.all([import('./module1.js'), import('./module2.js'), import('./module3.js')]).then(([module1, module2, module3]) => { /* ... */ });