Last updated on Oct 2, 2022
(没有讨论 dynamic import 这种情况)
ESM
// 导出方式
// named export
export { export1 }
// default export
export default defaultExport
// export from
export { export1 } from 'module-name'
// 导入方式
// named import
import { export1 } from 'module-name'
// default import
import defaultExport from 'module-name'
// namespace import
import * as name from 'module-name'
// side effect import
import 'module-name'
CJS
/ / 导出方式
// lib.cjs
module.exports = {
a: 1,
b: 2
}
// 和上面等价,算一种
exports.a = 1
exports.b = 2
// 导入
// main.cjs
const lib = require('./lib')
console.log('a:', lib.a)
console.log('b:', lib.b)
问题来了,ESM 和 CJS 如何进行互操呢?
复杂度:1. ESM 多种导入和导出方式;2. 不同平台的处理方式不同
不同平台:(包含不限于)Rollup、Webpack、Babel、TypeScript、浏览器、Node.js
ESM 推出之前,CJS 已经被广泛使用。为了解决 ESM 和 CJS 的互操问题,ESM 中 default 的导出名称被赋予了特殊的语法。
export default defaultExport
// 不需要写
import { default as foo } from 'bar'
// 而是直接写
import foo from 'bar'
对照
const a = 1
// 导出导入方式一
export { a }
import { a as foo } from 'bar'
console.log(foo) // 1
// 导出导入方式二
export default a
import foo from 'bar'
console.log(foo) // 1
所以当 CJS 导入 ESM 时,可以使用新的 ESM 语法来实现兼容:(例:lib.cjs 导入 main.mjs)
// lib.cjs
module.exports = {
a: 1,
b: 2,
}
// main.mjs
import lib from '../lib.cjs'
console.log(lib) // { a: 1, b: 2 }
// main.cjs
const lib = require('./lib.cjs')
console.log(lib) // { a: 1, b: 2 }
可以看到 CJS 导入 ESM 的行为和 CJS 导入 CJS 的行为一致。(即 import foo from 'bar' 等价于 const foo = require('bar'))