本文记录了一些 ESM 使用 以及 ESM 和 CommonJS 互相引用的知识点,假定你对 CommonJS 和 ESM 有一定的了解。 你也可以参考 阮一峰: ESM Module 的语法阮一峰: ESM Module 的加载实现 获取更多信息。

较新的 NodeJS 版本(>=13.2.0)可以加载 CommonJS 和 ESM,用户需指明具体某些文件是什么模块类型。可以简单参考如下:

image

ESM import 常用场景

一图胜千言:

image

import { add } from ‘moduleA’

此时 add 是 moduleA 导出的函数 add

// moduleA.mjs
export function add(a, b) {
  return a + b
}

import moduleA from ‘moduleA’

此时 moduleA 是 moduleA 导出的 default, 等价于import { default as moduleA } from 'moduleA'

// moduleA.mjs
export default {
  add: function(a, b) {
    return a + b
  }
}

import * as moduleA from ‘moduleA’

此时 moduleA 对应模块 moduleA 中的 namespace object, 可简单理解为所有导出的变量,包括default

// moduleA.mjs
export function add(a, b) {
  return a + b
}
export default function add(a, b) {
  return a + b
}

模块类型混乱引发的异常

如果 package.json 中 type = commonjs,尝试运行 ESM 文件,会报错

image

image

如果 package.json 中 type = moudle,尝试运行 CommonJS 文件,会报错

image

image

CommonJS 文件中引用 ESM 模块

使用场景较少,此处不谈论。

ESM 文件中引用 CommonJS 模块

// tool.cjs
function add(a, b) {
  return a + b
}

exports.add = add
// test.mjs

// 三种方式都可以
import { add } from './tool.cjs'
import Tool1 from './tool.cjs'
import * as Tool2 from './tool.cjs'

console.log(add(1, 2))
console.log(Tool1.add(1, 2))
console.log(Tool2.add(1, 2))

ESM 引用 CommonJS 模块时,等价于 export CommonJS 中 exports,同时 export default CommonJS 中 exports。所以 tool.cjs 可以等价于

// tool.mjs
function add(a, b) {
  return a + b
}

export { add }
export default { add }

一些模块已不再支持 CommonJS

chalk5.x 版本中完全使用 ESM 语法,不再支持 CommonJS。

image 其中背景可参见 Pure ESM package

如果你的代码还在使用 CommonJS,对于此类模块,只好使用旧版本。

做一个同时支持 CommonJS 和 ESM 的模块

技术上可以让一个模块同时兼容 CommonJS 和 ESM。官方参考文档:https://nodejs.org/api/packages.html#package-entry-points 方法是在模块中同时有 CommonJS 和 ESM 代码(加入分别在 cjs 和 mjs 子目录),在 package.json 中指明两者的入口文件。

// package.json
{
  "main": "./cjs/index.js",
  "module": "./mjs/index.js",
  "exports": {
    "require": "./cjs/index.js",
    "import": "./mjs/index.js"
  }
}

其中的 “exports” 是简写,等价于

// package.json
{
  "exports": {
    ".": {
      "require": "./cjs/index.js",
      "import": "./mjs/index.js"
    }
  }
}