从 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 这样的运行时来说,这是不值得的。
那么可以做什么呢?以下是我遇到此问题时一直在做的事情:
- 在包的仓库上打开问题以请求 ESM 版本。今天很多包在发布到 NPM 时将 ES6/TypeScript 模块转换为 CJS,它们可以很容易地 distribute an ESM version alongside the CJS one.
- 在您的依赖项上使用 https://github.com/mgechev/is-esm 来确定哪些支持指定的导入。
- 使用 https://github.com/ds300/patch-package 将 CJS 包转换为 ESM。
- 继续使用 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 这样的运行时来说,这是不值得的。
那么可以做什么呢?以下是我遇到此问题时一直在做的事情:
- 在包的仓库上打开问题以请求 ESM 版本。今天很多包在发布到 NPM 时将 ES6/TypeScript 模块转换为 CJS,它们可以很容易地 distribute an ESM version alongside the CJS one.
- 在您的依赖项上使用 https://github.com/mgechev/is-esm 来确定哪些支持指定的导入。
- 使用 https://github.com/ds300/patch-package 将 CJS 包转换为 ESM。
- 继续使用 std/esm 或捆绑器。只要它对你有用,那仍然是一个有效的选择。