我浏览了很多关于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 模块,而且它们具有复杂的依赖关系链,需要时间来解开。
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”),相同的逻辑仍然适用。有关详细信息,请参阅此处的答案:
希望这有帮助:)。