[JS] 模块系统ESM和CJS

简要说明二者的表象区别:

ESM 是ES6之后的JS模块规范。
CJS (CommonJS)是社区发展起来的主要应用于node.js应用的模块规范。

ESM模块规范使用import导入,export 、export default导出。
CJS模块规范使用require导入和exports、module.exports导出。

在一个npm init初始化的Node.js项目中,package.json里面type字段的设置决定.js文件用哪种模块规范加载。(type不写-> CJS加载。"type": "module" -> ESM加载)。此外.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CJS 模块加载。

重点说一说两个模块系统在使用时的区别:
不论以CJS、ESM中的哪种模块系统作为模块化开发的规范,(大部分情况下)最终都需要经过编译工具处理,编译成js文件,才能最终应用到生产环境。

再说一说两种模块规范的不同:

// ↓ ESM (情景1)

// a.js
const a = 1;
const b = "2";
export { a, b };
export default function() {
 console.log("default function done");
}
// b.js
import { a, b } from "./a.js";
import defaultFunc from "./a.js";
console.log(a); // 正常输出 1
console.log(b); // 正常输出 "2"
defaultFunc(); // 正常执行 -> "default function done"

// ↓ CJS (情景2)

// aa.js
const a = 1;
const b = "2";
exports.a = a;
exports.b = b;
module.exports = 3;

// bb.js
const bb= require("./aa.js");
console.log(bb); // 输出结果 3

对比情景1和情景2:
在ESM中
export default被视为顶级导出
export 被视为次级导出
两种导出方式不冲突,可以同时使用

在CJS中
module.exports被视为顶级导出
exports.x 被视为次级导出
顶级导出会覆盖次级导出(无论顶级导出的位置先后)

补充一个情景3
// ↓ CJS (情景3)

// cc.js
const a = 1;
const b = "2";
exports.a = a;
exports.b = b;

// dd.js
module.exports = 3;

// ee.js
module.exports = function() {
 console.log("default function done");
}

// ff.js
const cc = require('./cc.js');
const dd = require('./dd.js');
const ee= require('./ee.js');

console.log(cc); // 正常输出 { a: 1, b: '2' }
console.log("dd->", dd); // 正常输出 3
ee(); // 正常执行 -> "default function done"

上面的情景1、2、3基本涵盖了两个模块规范使用中出现的情况。ESM、CJS如果单独使用(即在一个工程里从头到尾使用ESM,或从头到尾使用CJS),都没有问题,编译工具会帮我们处理好各种情况。

但是一旦出现两种模块混用,就可能出现问题。两种模块混用,必然需要某种编译工具,使用的是编译后产物。

这里以ts-node为例。

// a.ts (ESM)
export default function () {
  console.log("default function done")
}

// b.ts (CJS)
const b = require("./a.ts");
//b(); // 直接执行顶级导出的函数会报错
b.default() // 必须使用default属性 -> 正常执行 "default function done"

工作中,我们尽量在单个工程中使用一种模块规范。如果真的遇到了上面的情景,需要ESM和CJS混用,最好是查阅工程所用的编译工具(如webpack、rollup、ts-node等等)的文档。看编译工具如何处理兼容问题。

举个例子,ts-node中的语法糖。
export = xxx;
import x = require('path/file');

完结。

同步更新到自己的语雀
https://www.yuque.com/diracke...

你可能感兴趣的:(前端javascript模块化)