我正在创建一个小型 Node.js 库,其源代码是用 TS 编写的,并且(理想情况下)生成的 JS 以 ESM 和 CJS 格式分发。
它有一个对等依赖项(当前为 CJS),我需要检测它是否已安装,如果没有则在继续之前提供后备。因此,我无法静态导入它,并且似乎需要在 ESM 发行版中使用动态
import
和 CJS 发行版中的 require
来检测它。
为了避免动态
import
迫使我将 Promise 导出给消费者,我正在考虑在 ESM 发行版中使用顶级 await
(因为自 Node 14.8.0 以来它一直支持未标记,这里的用例是类似于 tc39 提案中的这个)。所以生成的 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")
}
现在我有 2 个 tsconfig.json,一个用于 ESM,一个用于 CJS,我的源 TS 看起来与生成的 JS 的 ESM 版本一模一样。
我正在努力解决的是如何在 CJS 构建过程中用
await import
替换 require
,因为 TS 立即给出了一个硬停止,即 CJS 不支持顶级等待并获胜”继续。到目前为止,我还没有在 Typescript 的设置中找到任何可以启用此替换的内容,只有这个相关的 Github 问题用于解决想要按原样从 CJS 动态导入 ESM 模块的反向问题。
我当前的计划是添加构建前/构建后步骤来扫描我的 TS 源并执行查找和替换,然后运行 tsc,然后恢复源,尽管这看起来不太好。对于这个特定问题或尝试从单个 TS 源代码库支持 ESM/CJS 的更大问题的任何想法将不胜感激。
谢谢
我认为我最近编写的一个库import-sync满足了这个用例
该库是 esm 的包装器,支持从 ES6 和基于 CJS 的 NodeJS 项目导入 ESM。
对于基于 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
将同步动态导入模块。
希望这有帮助:)。