如何从同一节点 CLI 动态导入 commonJS 和 ES6 模块?

问题描述 投票:0回答:1

我浏览了很多关于SO的类似问题,但没有找到明确的答案。

我正在编写一个 npm CLI 工具,该工具应该动态导入指定的模块并对该模块的导出运行一些操作。

在我的 npm 包中,我指定了

"type": "module"
,我的二进制文件是
bin/generator.mjs

我尝试使用它的方式是:

❯ ./bin/generator.mjs path/to/test-module.js [other args]
- 然后在生成器中我这样做:

const modulePath = "file://" + path.resolve(inputFilename);
const objs = await import(modulePath);

通过此配置,我可以在命令行上指定 ES6 模块,并且生成器工作正常,但是,如果我指定 CommonJS 模块,我得到:

const Library = require('some-library');
                ^
ReferenceError: require is not defined

这是我的两个测试文件:

ES6模块

import Library from 'some-library';

export const person = { firstName: "Bob", lastName: "Mortimer };

CommonJS 模块

const Library = require('some-library');

const person = { firstName: "Bob", lastName: "Mortimer };
module.exports.person = person;

然后我尝试使用两个不同的二进制文件 -

generator
用于 ES6 模块,
generator-cjs
用于 CommonJS 模块 - 我修改了原始文件以使用
require
代替
import
,但是,
bin/generator.mjs
继续工作正常,但是
bin/generator.cjs
抛出此错误:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: [...]/test-module.js
require() of ES modules is not supported.
require() of [...]/test-module.js from [...]/bin/generator.cjs is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename test-module.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from [...]/package.json.

如果我从

"type": "module"
中删除
package.json
generator
generator-cjs
都可以在 CommonJS 文件上工作,但
generator
在 ES6 模块上抛出此错误:

throw new Error('Unexpected import statement in CJS module.');
            ^
Error: Unexpected import statement in CJS module.

理想情况下:我想要一个可以动态导入 CommonJS 和 ES6 模块的二进制文件。

如果您已阅读本文 - 谢谢。

您对我如何解决这个问题有什么想法吗?如果您希望我尝试提供更多信息,请告诉我。

谢谢,


编辑:我应该提到,将 CommonJS 模块转换为 ES6 并不是一个选择,因为有近一百个 CJS 模块,而且它们具有复杂的依赖关系链,需要时间来解开。

node.js ecmascript-6 node-modules dynamic-import module.exports
1个回答
0
投票

import-sync,我在 2023 年编写的一个库,也许可以帮助解决这个问题。

import-sync 围绕 esm,使您能够在运行时将 ESM/CJS 模块动态导入到基于 ESM/CJS 的项目中

您可以使用以下方式安装库:

npm install import-sync

然后按如下方式使用:

const importSync = require('import-sync'); // for CJS
import importSync from 'import-sync'; // for ESM

const someVariable = 'someModule';
if (someCondition) {
  const someModule = importSync(`../../someFolder/${someVariable}`);
  console.log(someModule);
}

CJS 导入 ESM、ESM 导入 CJS 等的任意组合都可以。

对于您的示例,由于您的 package.json 中有 "type": "module",因此设置可以是:

package.json

{
  "type": "module",
  "dependencies": {
    "import-sync": "^2.0.5",
    "node-fetch": "^3.3.2",
    "sync-request-curl": "^2.1.6"
  }
}

libcommon.js

const request = require('sync-request-curl');

module.exports = {
  request
};

libesm.js

import fetch from 'node-fetch';

export { fetch };

index.js

import importSync from 'import-sync';

const libCommonExport = importSync('./libcommon.js');
const libEsmExport = importSync('./libesm.js');

console.log('1. CommonJS:', libCommonExport);
console.log();
console.log('2. ESM:', libEsmExport);

因此,当在命令行中运行

node index.js
时,我们得到

$ node index.js
1. CommonJS: {
  request: <ref *1> [Function: request] {
    default: [Circular *1],
    CurlError: [class CurlError extends Error]
  }
}

2. ESM: { fetch: [AsyncFunction: fetch] }

这展示了两次导入是如何成功的。这是完整的项目图片:

对于 CJS 项目(即

package.json
中没有“type”:“module”),相同的逻辑仍然适用。有关详细信息,请参阅此处的答案:

希望这有帮助:)。

© www.soinside.com 2019 - 2024. All rights reserved.