ES module(ESM) 與 CommonJS比較
ES module | CommonJS | |
---|---|---|
類型 | ES6官方標準 | Node.js的預設標準 |
可運行環境 | 瀏覽器、Node(v13.2.0開始) | Node |
輸出語法 | export default | module.exports |
引入語法 | import ... from '...' | require('...') |
引入類型 | 非同步 | 同步 |
靜態引入 | 〇(只能在module頂層出現) | 〇 |
動態引入 | ✖ | 〇 |
修改導出的值 | ✖ | 〇 但可能造成變數汙染 |
重複引入同module | 都會運行 | 只會在第一次加載運行 |
JS環境
ESM
default導出時,default引入
export default(a, b) => { return a + b; }
// 因為是default,所以可以自己命名 imoprt abc from '../src/index.js';
多個導出時,只引用其中一個
export const sum(a, b) => { return a + b; } export const getDate(str) => { const regex = /(?<=[0-9]{4}-)[0-9]{2}-[0-9]{2}/; return str.match(regex); }
import {sum} from '../src/index.js';
多個導出時,引入全部
export const sum(a, b) => { return a + b; } export const getDate(str) => { const regex = /(?<=[0-9]{4}-)[0-9]{2}-[0-9]{2}/; return str.match(regex); }
// 可以自己命名 import * as utils from '../src/index.js';
混合導出時
export const sum(a, b) => { return a + b; } export default(a, b) => { return a * b; }
混合引入
// 這邊的abc是export default那個 import abc, {sum} from './src/index.js';
全部當作一個module引入
// 這邊的abc是兩個module的集合體 import * as abc from './src/index.js'; // 這是sum const sum = abc.sum; // 這是default const default = abc.default;
CommonJS
導出(module.exports) & 引入
const sum(a, b) => { return a + b; } const multiply = (a, b) => { return a * b; } module.exports = { sum, multiply }
// 全部引入 const utils = require('./src/index.js'); // 部分引入 const {sum, multiply} = require('./src/index.js');
導出(exports)
const sum(a, b) => { return a + b; } exports.sum = sum;
module.exports & exports
這兩個東西一開始都是指向一個空物件,所以下面這樣能達到同樣的效果,是因為做的都是在那個空物件裡頭新增一個sum屬性,並賦值。module.export.sum = (a, b) => { return a + b; } exports.sum = (a, b) => { return a + b; }
下面這樣exports會導出失敗,因為exports = ...,這個動作改變了exports的指向,它不再指向和module.exports同一個物件(那個最初的空物件)
module.exports.hello = true; // Exported from require of module exports = { hello: false }; // Not exported, only available in the module
ESM引入,CommonJS導出
// 詳細看參考資料
object.defineproperty(exports, '__esmodule', { value: true })
Node.js環境
預設標準目前仍是CommonJS
v13.2.0開始Node.js可以穩定支援ES module
v8.5.0開始透過--experimental-modules flag 還是可以在v8.5.0環境用ES module
nodemon --experimental-modules index.mjs
.js & .cjs & .mjs & .es.js 的差異
- .js:採取預設標準(CommonJS)
- .cjs:走CommonJS標準
- .mjs:走ESM標準
- .es.js:走ESM標準
將標準從CommonJS轉為ESM的方法
- 副檔名用.mjs
在package.json中將type設為module,這樣Node.js就會把package裡所有東西當ESM
{ "name": "my-library", "version": "1.0.0", "type": "module", // ... }
📖
CommonJS vs. ES modules in Node.js
__esModule 的作用
exports跟module.exports的差別 懶人包
關於ES6 模組系統