0%

day11-ModuleExport比較

摘自 居玉皓 的 Webpack實戰:入門、進階與調優
CommonJS, ES6 Module, AMD, UMD 做簡單的比較

CommonJS

模組 - 每個模組是擁有各自的作用域

CommonJS在每個模組都開頭添加了以下程式碼:

var module = {
exports: {},
};
var exports = module.exports;

導出 - 利用.export關鍵字

module.exports = {
name: 'calculater',
add: function(a, b) {
return a + b;
}
};

導入 - 利用require關鍵字

// calculator.js
module.exports = {
add: function(a, b) {return a + b;}
};
// index.js
const calculator = require('./calculator.js');
const sum = calculator.add(2, 3);
console.log(sum); // 5
  • require有兩種情況:
    • module是第一次被載入。首先執行該模組,然後導出內容。
    • module曾被加載入過。模組內的程式碼不會再次執行,而是直接導出上次執行後得到的結果。

ES6 Module

導出

// 命名導出 - 自訂關鍵字 or 使用as 
export const name = 'calculator';
export const add = function(a, b) { return a + b; };

// 默認導出 - default關鍵字
const name = 'calculator';
const add = function(a, b) { return a + b; };
export { name, add };

導入

// calculator.js
const name = 'calculator';
const add = function(a, b) { return a + b; };
export { name, add };

// ES6 Module中使用import語法導入模組
import * as calculator from './calculator.js';
import { name, add } from './calculator.js';
import React, { Component } from 'react';
add(2, 3);

這裡的React必須寫在大括號前面,而不能順序顛倒,否則會提示語法錯誤。

CommonJS與ES6 Module的區別

動態與靜態

  • CommonJS

    • require的模組可以動態指定,可以通過if語句判斷是否加載某個模組
    • 被執行前,並沒有辦法確定明確的依賴關係,模組的導入、導出發生在代碼的運行階段。
  • ES6 Module

    • 導入、導出語句都是聲明式的,它不支持導入的路徑是一個表達式,並且導入、導出語句必須位於模組的頂層作用域。因此我們說,ES6 Module是一種靜態的模組結構,在ES6代碼的編譯階段就可以分析出模組的依賴關係。好處是:
      • 死代碼檢測和排除。靜態分析工具檢測出哪些模組沒有被調用過。未被調模組永不執行->死代碼。打包時去掉死代碼,以減小打包資源體積。
      • 模組變量類型檢查。JavaScript屬於動態類型語言,不會在代碼執行前檢查類型錯誤(比如對一個字符串類型的值進行函數調用)。ES6 Module的靜態模組結構有助於確保模組之間傳遞的值或接口類型是正確的。
      • 編譯器優化。在CommonJS等動態模組系統中,無論採用哪種方式,本質上導入的都是一個對象,而ES6 Module支持直接導入變數,減少了引用層級,程序效率更高。
  • CommonJS是值拷貝/ ES6 Module是reference

非Module文件加載 - 如下:

import './jquery.min.js';

AMD

- Asynchronous Module Definition(異步模組定義)

它加載模組的方式是異步的。

// 導出
define('getSum', ['calculator'], function(math) {
return function(a, b) {
console.log('sum: ' + calculator.add(a, b));
}
});
// 導入
require(['getSum'], function(getSum) {
getSum(2, 3);
});

非阻塞性, 會繼續執行require後面的code, 但是語法冗長, 或許有callback hell.

UMD

Universal Module Definition,也就是通用模組標準

早在ES6還沒發布前, 算是一種集合體. 支持AMD, CommonJS

// calculator.js
(function (global, main) {
// 根據當前環境採取不同的導出方式
if (typeof define === 'function' && define.amd) {
// AMD
define(...);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = ...;
} else {
// 非模組化環境
global.add = ...;
}
}(this, function () {
// 定義模組主體
return {...}
}));