【问题标题】:CommonJS wrapper for ES module scriptsES 模块脚本的 CommonJS 包装器
【发布时间】:2020-09-13 22:31:23
【问题描述】:

Node documentation on ECMAScript Modules 建议向用户提供 CommonJS 脚本和 ES 模块脚本的“双包”。

具体来说,他们建议将 ES 模块脚本转译为 CommonJS,然后使用“ES 模块包装器”,这是一个 ES 模块脚本,它从 CJS 导入并将其名为 export 的 CJS 重新导出为名为 export 的 ESM。

// ./node_modules/pkg/wrapper.mjs
import cjsModule from './index.cjs';
export const name = cjsModule.name;

我的问题是:是否可以以相反的方式执行此操作,以 ES 模块格式提供我的脚本,但在 CommonJS 中添加一个简单的包装文件,允许 CJS 用户 require 它?

就我而言,我看不到在同步代码中执行此操作的方法。在我看来,CommonJS 脚本只能通过异步动态import() 导入 ES 模块。

(async () => {
    const {foo} = await import('./foo.mjs');
})();

但这意味着我的 CJS 脚本无法导出任何依赖于 foo 的内容。

【问题讨论】:

  • @jfriend00 我认为您正在回答相反的问题。你在告诉我为什么 ES 模块不能import {foo} from './foo.cjs',但我想知道 CommonJS 是否可以const {foo} = importSync('./foo.mjs')(或者,如果不能,为什么不能)
  • ES 模块在语法上与没有它的 js 版本不兼容。所以importSync 需要即时转译代码。
  • @YuryTarabanko 已经可以使用import() 在 Node 14 的 CJS 中导入 ESM,而无需转译。我只想同步做。
  • "我的 CJS 脚本无法导出任何依赖于 foo 的内容。" - 他们总是可以为它导出一个 Promise :-)

标签: javascript es6-modules commonjs


【解决方案1】:

There is no way to synchronously import ESM modules. CJS 导出是同步的,但 ESM 导入本质上是异步的。

在 CommonJS 中,require() 是同步的; 它不返回承诺或 调用回调。 require() 从磁盘读取(甚至可能从 网络),然后立即运行脚本,该脚本本身可能 做 I/O 或其他副作用,然后返回任何值 设置为module.exports

在 ESM 中,模块加载器在异步阶段运行。 阶段,它解析脚本以检测对导入和导出的调用 不运行导入的脚本。在解析阶段,ESM loader 可以立即检测命名导入中的拼写错误并抛出 没有实际运行依赖代码的异常。

ESM 模块加载器然后异步下载并解析任何 您导入的脚本,然后是您的脚本的脚本 导入,构建依赖关系的“模块图”,直到 最终它找到了一个不导入任何东西的脚本。最后, 该脚本被允许执行,然后是依赖于的脚本 允许运行,等等。

甚至不一定在所有情况下都可以 ESM 转换为 CJS。例如,ESM 可以使用top-level await,而 CJS 模块则不能。因此,无法将此 ESM 代码转换为 CJS:

export const foo = await fetch('./data.json');

CJS 和 ESM 是完全不同的动物。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    • 2021-11-05
    • 2021-11-20
    • 1970-01-01
    • 2021-12-02
    • 2022-08-16
    • 2022-12-14
    相关资源
    最近更新 更多