从 std/esm 迁移到节点 V14 中的 esm 支持 - 找不到命名导入 - 与 std/esm 一起工作正常

Migrating from std/esm to esm support in node V14 - can't find named import - works fine with std/esm

第一次使用一年+ 我已经使用 esm 和 std/esm 包编写了我所有的代码,我能够无缝地使用带有 cjs 的依赖包而无需 babel。

在 nodejs V14 中,混合 esm/cjs 支持现在包含在没有标志的情况下,std/esm 项目似乎正在结束,所以我想我应该尝试迁移以查看问题可能是什么。好吧,我找到了。

https://github.com/standard-things/esm

https://nodejs.org/api/esm.html#esm_ecmascript_modules

我遇到的问题是,与 std/esm 不同,现在包含在 V14 nodejs 中的 esm/cjs 支持正在破坏命名导入(我假设是 commonjs 模块导出) std/esm.

没问题

https://github.com/sindresorhus/make-dir/blob/978bee9186bf0c41640ed21567921daf8c303225/index.js#L106

为例

as packages 是使用 cjs。这是出口

module.exports.sync = (input, options) => {
    checkPath(input);
    options = processOptions(options);

在我的 package.json 中使用 "type":"module"。我的代码中有导入 import { sync as mkdir } from 'make-dir' ,使用 std/esm 效果很好。但是在 nodejs 14 中使用它说它找不到命名的导出 sync.**

import { sync as mkdir } from 'make-dir'
         ^^^^
SyntaxError: The requested module 'make-dir' does not provide an export named 'sync'

我被困在这里了吗?我需要留在 std/esm 吗? (但看起来这个项目现在已经结束了)我不能't/shouldn 无法通过

包含 cjs 模块的整个代码库
import mk from 'make-dir'
const mkdir = mk.sync

为了让任何人都可以轻松地重新创建,我制作了一个可以克隆的 repo,运行 看到了这个区别

https://github.com/dkebler/core-esm-named-import-error

无论如何,假设 v14 中的 esm 将替代使用 std/esm。显然不是:(。

编辑:从 Node.js 14.13.0(和 Node.js 12.19.0 LTS)开始,导入 CJS 模块使用 https://github.com/guybedford/cjs-module-lexer 解析文件以检测最常见的命名导出,所以你可以使用来自 ESM 的那些。原始答案已过时,但仍然有助于理解为什么 Node.js 未检测到某些 CJS 命名导出。

技术原因 Node.js 只支持 CJS 脚本的默认导出是因为 ESM import 是静态的(它在模块执行之前被解析)而 CJS module.exports 是动态的(你可以做一些像 module.exports[Date.now()] = 0 这样疯狂的事情并逃脱惩罚)。确定 CJS 模块导出的“名称”的唯一方法是解析和执行它,这似乎与 ES6 规范不兼容。

一些捆绑器(例如 std/esm)在 CJS 模块代码中使用正则表达式来查找 module.exports.<named export> = 的实例,并使用它来定义模块的命名导出列表。这种方法的缺点是你不会找到所有的出口,大文件的解析可能会非常占用内存。这也意味着解析 CJS 模块两次,虽然性能损失对于打包器来说可能还可以,但对于像 Node.js 这样的运行时来说,这是不值得的。

那么可以做什么呢?以下是我遇到此问题时一直在做的事情: