Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NodeJS 模块系统备忘:CommonJS & ESM #67

Open
isayme opened this issue Nov 8, 2023 · 0 comments
Open

NodeJS 模块系统备忘:CommonJS & ESM #67

isayme opened this issue Nov 8, 2023 · 0 comments

Comments

@isayme
Copy link
Owner

isayme commented Nov 8, 2023

本文记录了一些 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"
    }
  }
}
@isayme isayme changed the title NodeJS 模板备忘:CommonJS & ESM NodeJS 模块系统备忘:CommonJS & ESM Nov 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant