在一个同时面向ESM和CJS的基于Typescript的项目中,如何将“动态导入的顶级等待”转换为“同步请求”?

xdnvmnnf  于 12个月前  发布在  TypeScript
关注(0)|答案(1)|浏览(115)

我正在创建一个小型的Node.js库,源代码用TS编写,(理想情况下)生成的JS以ESM和CJS格式分发。
它有一个对等依赖(目前是CJS),我需要检测它是否安装,如果没有,在继续之前提供一个回退。因此,我不能静态地导入它,似乎需要在ESM发行版中使用动态import,在CJS发行版中使用require来检测它。
为了避免动态import单独迫使我将Promise导出到消费者,我正在考虑在ESM发行版中使用顶级await(因为它自Node 14.8.0以来一直支持无标记,这里的用例与tc 39提案中的用例类似)。所以生成的JS看起来像
ESM:

try {
    peerExport = await import("the-cjs-peer-dependency") //Notice this isn't inside of an async block
}

CJS:

try {
   peerExport = require("the-cjs-peer-dependency")
}

现在我有两个tsjs.json,一个用于ESM,一个用于CJS,我的源TS看起来和生成的JS的ESM版本完全一样。
我正在努力解决的是如何在CJS构建过程中用require替换await import,因为TS立即给出了一个硬停止,CJS不支持顶级等待,不会继续。到目前为止,我还没有在Typescript的设置中找到任何可以启用这种替换的东西,只有这个related Github issue解决了一个相反的问题,即希望保持从CJS模块中动态导入ESM模块。
我目前的计划是添加构建前/构建后的步骤来扫描我的TS源代码,并执行查找和替换,然后运行tsc,然后恢复源代码,尽管这似乎不是很好。任何关于这个特定问题的想法,或者试图在单个TS源代码库中支持ESM/CJS的更大问题,都将受到欢迎。
谢谢

ffdz8vbo

ffdz8vbo1#

import-sync是我在2023年编写的一个库,它将有助于同步动态导入。

该库是esm的 Package 器,支持将CJS/ESM导入到ES6和基于CJS的NodeJS项目中。
对于基于CJS的NodeJS项目:

/*
 * index.js/index.cjs
 */
const importSync = require('import-sync');
const { sum } = importSync('./sum.js');
console.log(sum(2,3)); // prints 5

对于基于ESM的NodeJS项目:

/*
 * index.mjs/index.js with "type": "module" in package.json
 */
import importSync from 'import-sync';
const { sum } = importSync('./sum.js');
console.log(sum(2,3)); // prints 5

文件sum.js可以是CJS或ESM -importSync将同步和动态导入模块。
具体到你的情况,你可以简单地做

try {
    peerExport = importSync("the-cjs-peer-dependency");
}

而不用担心是否使用了CJS或ESM。
希望这对你有帮助:)

相关问题