On this page
commonjs与es模块的互操作
Mar 15, 2022
为了解决 ESM 和 CJS 的交互性问题,名为 default 的导出名称被赋予了特殊的语法。
import { default as cjs } from 'cjs';
import cjsSugar from 'cjs';
在 nodejs 中,require() 命令是不能加载 ES 模块的,只能使用 import() 方法加载。
不支持的原因是他是同步加载的,而 ES 模块内部可以在顶层使用 await 命令,导致无法被同步加载。
export const a = 1;
export default 2;
const foo = require('foo.ejs');
CommonJS 模块的 ECMAScript 模块命名空间表示始终是使用 default 导出键指向 CommonJS module.exports 值的命名空间。
当使用 import * as m from 'cjs' 或动态导入时,可以直接观察到此模块命名空间外来对象。
import * as m from 'cjs';
console.log(m);
console.log(m === (await import('cjs')));
为了更好地兼容 JS 生态系统中的现有用法,Node.js 还尝试确定每个导入的 CommonJS 模块的 CommonJS 命名导出,以使用静态分析过程将它们作为单独的 ES 模块导出提供。
exports.name = 'exported';
import { name } from './cjs.cjs';
console.log(name);
import cjs from './cjs.cjs';
console.log(cjs);
import * as m from './cjs.cjs';
console.log(m);
module.exports = 'exported';
import { name } from './cjs.cjs';
console.log(name);
import cjs from './cjs.cjs';
console.log(cjs);
import * as m from './cjs.cjs';
console.log(m);
exports.a = 'a';
module.exports = 'exported';
import { a } from './cjs.cjs';
console.log(a);
import cjs from './cjs.cjs';
console.log(cjs);
import * as m from './cjs.cjs';
console.log(m);
export default 0 ==> module.exports.default = 0
import foo from 'foo' ==> const foo = require('foo')
这里产生了不一致的行为,es 的 foo 为 0 , cjs 的 foo 为 { default: 0 }
babel 为了解决这个问题,增加了 __esModule 属性,为 true 表示 require 了一个 es 模块。
所以 cjs 的 foo 变成了为 { default: 0, __esModule: true }
需要注意的是,nodejs 的实现与 babel 编译的实现是不一样的。
对 nodejs 来说,default 导出是等同于 module.exports 的!!! (这句话很重要,但我似乎不是很理解这话是对是错的)