# cjs-module-lexer 中文文档

规范地址：https://npmcn.com/package/cjs-module-lexer/

版本：2\.3\.0
npm 元数据更新时间：2026-10-05T07:57:24.493Z
中文译文更新时间：2026-11-05T14:50:17.237Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/cjs-module-lexer
原文对照：https://npmcn.com/package/cjs-module-lexer/?lang=original
项目主页：https://github.com/nodejs/cjs-module-lexer#readme
源码仓库：https://github.com/nodejs/cjs-module-lexer

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：142 kB，8 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2020-05-14T08:53:02.937Z
- 最新版本发布：2026-10-05T07:57:24.285Z
- 近 30 天下载量：456127425（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：49（近 12 个月 4 个）

## 中文简介

Lexes CommunityJS 模块,返回其命名的导出元数据

## 安装

```sh
npm install cjs-module-lexer
```

也可以使用：`pnpm add cjs-module-lexer`、`yarn add cjs-module-lexer`、`bun add cjs-module-lexer`

## README

# CJS 模块Lexer

[![Build Status](https://travis-ci.org/guybedford/es-module-lexer.svg?branch=master)](https://travis-ci.org/guybedford/es-module-lexer)

A 类 [非常快的,我马上回来](https://npmcn.com/package/cjs-module-lexer/#readme-benchmarks) JS CommunityJS模块的语法用词法来检测一个 CommunityJS模块最有可能的被命名导出列表.

输出命名的导出列表( E)`exports.name = ...`)和可能的模块再出口(`module.exports = require('...')`包括这些案件的常见变异.

从 [https://github.com/guybedford/es-module-lexer 页面存档备份,存于互联网档案馆](https://github.com/guybedford/es-module-lexer)。 。 。 .

_综合处理JS语言语法,同时保持小而快. - JS冷的每MB为90ms;JS热的每MB为15m, [参见基准](https://npmcn.com/package/cjs-module-lexer/#readme-benchmarks) 需要更多信息._

### 项目状况

该项目在Node.js核心中用于检测在将CJS模块导入无害环境管理时可用的指定出口,并为此目的加以维护.

PR会被接受并上游,仅用于解析器错误,性能改进或新的语法支持.

_该项目的检测模式是 **冻结**_。这是因为添加任何新的出口检测模式都会导致向后兼容性支离破碎。 具体地说,很难理解为什么一个名为Export for CommunityJS的ES模块可能会在更新的Node.js版本中工作,但不会在更旧的版本中工作. 这个问题只能在模块作者的下游发现,然后模块作者的固定方法必须了解该项目中哪些模式可以完全反向兼容。 相反,通过完全冻结所发现的图案,如果在任何节点.js版本中有效,它将在任何其他版本中有效。 构建工具也可以可靠地将这个项目所支持的语法作为其确保语法支持的产出目标的一部分.

### 使用量

```
npm install cjs-module-lexer
```

用于通用JS:

```js
const { parse } = require('cjs-module-lexer');

// `init` return a promise for parity with the ESM API, but you do not have to call it

const { exports, reexports } = parse(`
  // named exports detection
  module.exports.a = 'a';
  (function () {
    exports.b = 'b';
  })();
  Object.defineProperty(exports, 'c', { value: 'c' });
  /* exports.d = 'not detected'; */

  // reexports detection
  if (maybe) module.exports = require('./dep1.js');
  if (another) module.exports = require('./dep2.js');

  // literal exports assignments
  module.exports = { a, b: c, d, 'e': f }

  // __esModule detection
  Object.defineProperty(module.exports, '__esModule', { value: true })
`);

// exports === ['a', 'b', 'c', '__esModule']
// reexports === ['./dep1.js', './dep2.js']
```

在使用无害环境管理版本时,瓦斯姆得到支持:

```js
import { parse, init } from 'cjs-module-lexer';
// In browsers, initialize the Wasm before parsing.
await init();
const { exports, reexports } = parse(source);
```

`parse` 电话 `initSync()` 如果初始化尚未完成,则在第一次使用时使用. 打电话 `initSync()` 直接选择屏蔽初始化运行时. 浏览器主线程可以限制同步 Wasm 编译, 所以等待 `init()` 在浏览器中解析之前.

瓦斯姆的建筑速度在1.5x左右,没有冰冷起步.

### 语法

CommunityJS导出匹配项运行于源令牌流.

符号语法是:

```
IDENTIFIER: As defined by ECMA-262, without support for identifier `\` escapes, filtered to remove strict reserved words:
            "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield", "enum"

STRING_LITERAL: A `"` or `'` bounded ECMA-262 string literal.

MODULE_EXPORTS: `module` `.` `exports`

EXPORTS_IDENTIFIER: MODULE_EXPORTS_IDENTIFIER | `exports`

EXPORTS_DOT_ASSIGN: EXPORTS_IDENTIFIER `.` IDENTIFIER `=`

EXPORTS_LITERAL_COMPUTED_ASSIGN: EXPORTS_IDENTIFIER `[` STRING_LITERAL `]` `=`

EXPORTS_LITERAL_PROP: (IDENTIFIER  (`:` IDENTIFIER)?) | (STRING_LITERAL `:` IDENTIFIER)

EXPORTS_SPREAD: `...` (IDENTIFIER | REQUIRE)

EXPORTS_MEMBER: EXPORTS_DOT_ASSIGN | EXPORTS_LITERAL_COMPUTED_ASSIGN

EXPORTS_DEFINE: `Object` `.` `defineProperty `(` EXPORTS_IDENFITIER `,` STRING_LITERAL

EXPORTS_DEFINE_VALUE: EXPORTS_DEFINE `, {`
  (`enumerable: true,`)?
  (
    `value:` |
    `get` (`: function` IDENTIFIER? )?  `() {` return IDENTIFIER (`.` IDENTIFIER | `[` STRING_LITERAL `]`)? `;`? `}` `,`?
  )
  `})`

EXPORTS_LITERAL: MODULE_EXPORTS `=` `{` (EXPORTS_LITERAL_PROP | EXPORTS_SPREAD) `,`)+ `}`

REQUIRE: `require` `(` STRING_LITERAL `)`

EXPORTS_ASSIGN: (`var` | `const` | `let`) IDENTIFIER `=` (`_interopRequireWildcard (`)? REQUIRE

MODULE_EXPORTS_ASSIGN: MODULE_EXPORTS `=` REQUIRE

EXPORT_STAR: (`__export` | `__exportStar`) `(` REQUIRE

EXPORT_STAR_LIB: `Object.keys(` IDENTIFIER$1 `).forEach(function (` IDENTIFIER$2 `) {`
  (
    (
      `if (` IDENTIFIER$2 `===` ( `'default'` | `"default"` ) `||` IDENTIFIER$2 `===` ( '__esModule' | `"__esModule"` ) `) return` `;`?
      (
        (`if (Object` `.prototype`? `.hasOwnProperty.call(`  IDENTIFIER `, ` IDENTIFIER$2 `)) return` `;`?)?
        (`if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`)?
      )?
    ) |
    `if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) (`&& !` (`Object` `.prototype`? `.hasOwnProperty.call(`  IDENTIFIER `, ` IDENTIFIER$2 `)` | IDENTIFIER `.hasOwnProperty(` IDENTIFIER$2 `)`))? `)`
  )
  (
    EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] =` IDENTIFIER$1 `[` IDENTIFIER$2 `]` `;`? |
    `Object.defineProperty(` EXPORTS_IDENTIFIER `, ` IDENTIFIER$2 `, { enumerable: true, get` (`: function` IDENTIFIER? )?  `() { return ` IDENTIFIER$1 `[` IDENTIFIER$2 `]` `;`? `}` `,`? `})` `;`?
  )
  `})`
```

令牌之间的间距取为任意ECMA-262白相间,ECMA-262块注释或ECMA-262行注释.

-   返回的导出名称为:
    1.  全体 `IDENTIFIER` 财务报告和审定财务报表 `STRING_LITERAL` 用于 `EXPORTS_MEMBER` 财务报告和审定财务报表 `EXPORTS_LITERAL` 火柴。 比赛.
    2.  第一个 `STRING_LITERAL` 全部时间档 `EXPORTS_DEFINE_VALUE` 匹配该字符串不是同一字符串的地方 `EXPORTS_DEFINE` 匹配这个不是同时 `EXPORTS_DEFINE_VALUE` 相匹配的。 匹配的.
-   再出口的规格是:
    1.  这个 `REQUIRE` 匹配最后一个匹配的任意 `MODULE_EXPORTS_ASSIGN` 或者说 `EXPORTS_LITERAL`。 。 。 .
    2.  全体 _顶级_ `EXPORT_STAR` `REQUIRE` 匹配和 `EXPORTS_ASSIGN` 匹配其 `IDENTIFIER` 也匹配第一个 `IDENTIFIER` 内 `EXPORT_STAR_LIB`。 。 。 .

### 解析示例

#### 命名的导出解析

命名出口的基本匹配规则是 `exports.name`, (中文(简体) ), `exports['name']` 或者说 `Object.defineProperty(exports, 'name', ...)`。这种匹配没有范围分析,也不管表达位置如何:

```js
// DETECTS EXPORTS: a, b
(function (exports) {
  exports.a = 'a'; 
  exports['b'] = 'b';
})(exports);
```

由于没有范围分析,上述检测可能过度分类:

```js
// DETECTS EXPORTS: a, b, c
(function (exports, Object) {
  exports.a = 'a';
  exports['b'] = 'b';
  if (false)
    exports.c = 'c';
})(NOT_EXPORTS, NOT_OBJECT);
```

如果识别资料被重新命名,它又会降低分类:

```js
// DETECTS: NO EXPORTS
(function (e) {
  e.a = 'a';
  e['b'] = 'b';
})(exports);
```

#### Getter 导出分析

`Object.defineProperty` 检测到特定值和返回标识符或成员表达式的获取表:

```js
// DETECTS: a, b, c, d, __esModule
Object.defineProperty(exports, 'a', {
  enumerable: true,
  get: function () {
    return q.p;
  }
});
Object.defineProperty(exports, 'b', {
  enumerable: true,
  get: function () {
    return q['p'];
  }
});
Object.defineProperty(exports, 'c', {
  enumerable: true,
  get () {
    return b;
  }
});
Object.defineProperty(exports, 'd', { value: 'd' });
Object.defineProperty(exports, '__esModule', { value: true });
```

还特别检测出价值属性:

```js
Object.defineProperty(exports, 'a', {
  value: 'no problem'
});
```

为了避免匹配具有副作用的获取器,任何不支持上述表单的导出名称的获取器都会 选择退出匹配的获取器 :

```js
// DETECTS: NO EXPORTS
Object.defineProperty(exports, 'a', {
  get () {
    return 'nope';
  }
});

if (false) {
  Object.defineProperty(module.exports, 'a', {
    get () {
      return dynamic();
    }
  })
}
```

未检测到其它对象定义结构或获取器函数机构:

```js
// DETECTS: NO EXPORTS
Object.defineProperty(exports, 'a', {
  enumerable: false,
  get () {
    return p;
  }
});
Object.defineProperty(exports, 'b', {
  configurable: true,
  get () {
    return p;
  }
});
Object.defineProperty(exports, 'c', {
  get: () => p
});
Object.defineProperty(exports, 'd', {
  enumerable: true,
  get: function () {
    return dynamic();
  }
});
Object.defineProperty(exports, 'e', {
  enumerable: true,
  get () {
    return 'str';
  }
});
```

`Object.defineProperties` 也不予支持.

#### 导出对象指定

做了最好的检测 `module.exports` 对象任务,但是由于这不是一个全解析器,任意表达式不会在 对象解析进程.

支持简单的对象定义 :

```js
// DETECTS EXPORTS: a, b, c
module.exports = {
  a,
  'b': b,
  c: c,
  ...d
};
```

非标识符或字符串表达式的对象属性会从对象检测中跳出,而扩展被忽略:

```js
// DETECTS EXPORTS: a, b
module.exports = {
  a,
  ...d,
  b: require('c'),
  c: "not detected since require('c') above bails the object detection"
}
```

`Object.defineProperties` 目前也没有支持.

#### 模块

任意 `module.exports = require('mod')` 任务被检测为再出口, 但只返回最后一个:

```js
// DETECTS REEXPORTS: c
module.exports = require('a');
(module => module.exports = require('b'))(NOT_MODULE);
if (false) module.exports = require('c');
```

这是为了避免在Webpack包中与外部包件(包括: `module.exports = require('external')` 在他们的来源 对于每个外部依赖.

在导出对象任务中,任何扩展 `require()` 检测为多个单独的再出口:

```js
// DETECTS REEXPORTS: a, b
module.exports = require('ignored');
module.exports = {
  ...require('a'),
  ...require('b')
};
```

#### 转接器再出口

对于已命名的出口,转接器产出与上述规则十分相通.

但对于恒星再出口,要特别注意支持从Babel和TypeScript以及RollupJS等捆绑器输出的普通模式. 这些再出口和再出口模式仅限于通过这些工具的直接输出在顶层检测.

譬如说, `export * from 'external'` 由 Babel 输出为:

```js
"use strict";

exports.__esModule = true;

var _external = require("external");

Object.keys(_external).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  exports[key] = _external[key];
});
```

这里 `var _external = require("external")` 专门检测到的以及 `Object.keys(_external)` 语句, 准确到 包括产出的细微变化。 这个 `_external` 财务报告和审定财务报表 `key` 在此仔细匹配标识符 检测.

类似类型脚本, `export * from 'external'` 输出为:

```js
"use strict";
function __export(m) {
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("external"));
```

这里 `__export(require("external"))` 语句被明确检测为再出口,包括变异 `tslib.__export` 财务报告和审定财务报表 `__exportStar`。 。 。 .

### 环境支助

节点.js 10+,以及 [所有有Web Assembly支持的浏览器](https://caniuse.com/#feat=wasm)。 。 。 .

### JS 语法支持

-   Token状态解析出所有行注释,块注释,字符串,模板字符串,块,parens和活页符.
-   分区操作员/ regex 符号模糊是通过回溯检查处理的,包括关闭牙套或剖面回溯跟踪.
-   总是正确分析有效的JS来源,但可以毫无错误地分析无效的JS来源.

### 基准

可使用 `npm run bench`。 。 。 .

目前的结果:

联合来文:

```
Module load time
> 4ms
Cold Run, All Samples
test/samples/*.js (3635 KiB)
> 299ms

Warm Runs (average of 25 runs)
test/samples/angular.js (1410 KiB)
> 13.96ms
test/samples/angular.min.js (303 KiB)
> 4.72ms
test/samples/d3.js (553 KiB)
> 6.76ms
test/samples/d3.min.js (250 KiB)
> 4ms
test/samples/magic-string.js (34 KiB)
> 0.64ms
test/samples/magic-string.min.js (20 KiB)
> 0ms
test/samples/rollup.js (698 KiB)
> 8.48ms
test/samples/rollup.min.js (367 KiB)
> 5.36ms

Warm Runs, All Samples (average of 25 runs)
test/samples/*.js (3635 KiB)
> 40.28ms
```

Wasm 构建 :

```
Module load time
> 10ms
Cold Run, All Samples
test/samples/*.js (3635 KiB)
> 43ms

Warm Runs (average of 25 runs)
test/samples/angular.js (1410 KiB)
> 9.32ms
test/samples/angular.min.js (303 KiB)
> 3.16ms
test/samples/d3.js (553 KiB)
> 5ms
test/samples/d3.min.js (250 KiB)
> 2.32ms
test/samples/magic-string.js (34 KiB)
> 0.16ms
test/samples/magic-string.min.js (20 KiB)
> 0ms
test/samples/rollup.js (698 KiB)
> 6.28ms
test/samples/rollup.min.js (367 KiB)
> 3.6ms

Warm Runs, All Samples (average of 25 runs)
test/samples/*.js (3635 KiB)
> 27.76ms
```

### Wasm 构建步骤

建筑使用道克并制造,必须先安装.

要建立 Lexer 运行 `npm run build-wasm`建造时没有插头, `npm run build-wasm-local` 下载相同的被绑定的 idi-sdk 和 二进制版本 `build/toolchain` 并用这些建房.

最佳通行证是用 [二进制](https://github.com/WebAssembly/binaryen) 在出版之前减少Web大会足迹.

在建造了 Lexer 之后, 建造最后的分发组件 (lexer.js和lexer.mjs)通过运行 `npm run build`。 。 。 .

如果您需要建立 lib/lexer.wat (可选) 您必须首先安装 [华布](https://github.com/WebAssembly/wabt) 作为此的兄弟姐妹文件夹 项目。 然后通过运行构建 wat 文件 `make lib/lexer.wat`

### 创建释放

这些是创建和出版发行品的步骤. 你需要个插头 已安装或已安装 [华布](https://github.com/WebAssembly/wabt) 如上所述:

-   [ ] 确定该发布是否应该根据自此以来的变化进行成片补丁、小补丁或主要补丁 ,然后确定新版本.
-   [ ] 更新 package.json 版本,并运行完整的构建和测试
    -   npm 安装
    -   npm 运行构建
    -   npm 运行测试
-   [ ] 提交并标记更改, 推到主和标签
    -   举个例子
        -   `git tag -a 1.4.2 -m "1.4.2"`
        -   `git push origin tag 1.4.2`
-   [ ] 创建 GitHub 发布
-   [ ] 运行 npm 发布有访问权限的账户( 询问有访问权限的人) 节点创建账户是一个选项 如果你没有权限.

### 许可证

麻省理工学院

## 常见问题

### cjs-module-lexer 是什么？

Lexes CommunityJS 模块,返回其命名的导出元数据

### 如何安装 cjs-module-lexer？

在项目目录运行 npm install cjs-module-lexer，或使用 pnpm add / yarn add / bun add。

### cjs-module-lexer 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### cjs-module-lexer 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### cjs-module-lexer 可以商用吗？

cjs-module-lexer 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### cjs-module-lexer 的下载量有多少？

根据 npm 官方下载统计，cjs-module-lexer 在 2026/10/05 – 2026/11/03 这 30 天内被下载 456,127,425 次，日均约 15,204,248 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### cjs-module-lexer 还在维护吗？

最新版本 2\.3\.0 发布于 2026/10/05（1 个月前）；至今共发布 49 个版本，其中过去 12 个月发布了 4 个；首次发布于 2020/05/14。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

