> For the complete documentation index, see [llms.txt](https://coolconan.gitbook.io/roadmap/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://coolconan.gitbook.io/roadmap/back-end/languages/node/201030-node-esmodule-cmd.md).

# NodeJS 中的 esModule 与 commonJS

NodeJS 从 v14 版本开始正式支持解析 esModule，通过扩展 `.mjs` 或 `.cjs` 后缀，可以将 js 文件解析为 esModule 和 commonJS。

此外，也可以在文件目录下单独设置一个 `package.json`，声明 `{ "type": "module }`，默认在当前目录下使用 esModule 规范，进行模块解析。

那么，Node 当中的 esModule 和 commonJS 有哪些不同呢？

## 模块加载

**在 commonJS 中**，`require()` 的执行是同步的。它在调用后并不会返回一个 Promise 或者回调函数，而是直接从磁盘或者网络中读取资源（可能涉及到磁盘或网络的 I/O），并立即执行脚本中的内容，返回最后将 `module.exports` 的值。

**在 esModule 中**，模块的加载是异步的。首先，模块解析器（`module loader`）会对脚本进行静态解析，无需执行脚本中的内容，就可以分析出所有的 `import` 和 `export` 调用。在解析过程中，解析器可以快速地检查脚本引入或导出模块时的语法错误，并及时抛出异常。

esModule 的解析器会异步的下载与解析代码中引入的脚本，递归的分析模块间的引用关系，构建出完成的「模块依赖图谱」（`module graph`）。当解析完成后，对应的脚本以及它所依赖的脚本，就可以等待执行了。

所有的脚本都是并行下载的，并且按照引入顺序执行。

## 路径解析

在 esModule 中使用 `import` 时，必须完成声明文件路径，包括文件扩展名，如 `'./src/index.js'`。

在 node v14 版本中，使用 esModule 必须遵守 `file:` 协议，即 `URL-based paths`。

## 环境变量

commonJS 中的环境变量/对象，包括 `require`, `exports`, `module.exports`, `__filename`, `__dirname`，在 esModule 中都是无法使用的。

如果需要在 esModule 使用 `require`，可以通过 `module.createRequire()`。

如果需要使用 `__filename`, `__dirname`，可以通过 `import.meta.url` 进行读取。

```javascript
import { fileURLToPath } from 'url';
import { dirname } from 'path';

console.log(import.meta.url);

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
```

## `require.cache`

esModule 中无法使用 `require.cache`，而 commonJS 会缓存引入模块的相关信息。每次 require 模块后，commonJS 会缓存对应的模块，从 cache 中删除某个模块，那么下一次 require 会重新加载这个模块。

commonJS 中 `require.cache` 的数据结构如下：

```javascript
{
  "/esModule-cmd/cmd/env/index.js": {
    "id": ".",
    "path": "/esModule-cmd/cmd/env",
    "exports": {},
    "parent": null,
    "filename": "/esModule-cmd/cmd/env/index.js",
    "loaded": false,
    "children": [[Module]],
    "paths": [
      "/esModule-cmd/cmd/env/node_modules",
      "/esModule-cmd/cmd/node_modules",
      "/esModule-cmd/node_modules",
      "/node_modules"
    ]
  },
  "/esModule-cmd/cmd/env/a.js": {
    "id": "/esModule-cmd/cmd/env/a.js",
    "path": "/esModule-cmd/cmd/env",
    "exports": {},
    "parent": {
      "id": ".",
      "path": "/esModule-cmd/cmd/env",
      "exports": {},
      "parent": null,
      "filename": "/esModule-cmd/cmd/env/index.js",
      "loaded": false,
      "children": [Array],
      "paths": [Array]
    },
    "filename": "/esModule-cmd/cmd/env/a.js",
    "loaded": false,
    "children": [[Module]],
    "paths": [
      "/esModule-cmd/cmd/env/node_modules",
      "/esModule-cmd/cmd/node_modules",
      "/esModule-cmd/node_modules",
      "/node_modules"
    ]
  }
}
```

## 参考

* [Node Modules at War: Why CommonJS and ES Modules Can’t Get Along](https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1)
* [Modules: Packages](https://nodejs.org/docs/latest-v14.x/api/packages.html)
* [Modules: ECMAScript modules](https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_modules_ecmascript_modules)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://coolconan.gitbook.io/roadmap/back-end/languages/node/201030-node-esmodule-cmd.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
