为何Node.js中部分无默认导出的ESM包可被默认导入?
问题:为什么无默认导出的ESM包有的能默认导入,有的不行?
场景复现
自己编写一个ESM模块:
// greetings.js export const hello = 'hello'; export const hi = 'hi';
尝试用默认导入方式引入:
import greetings from './greetings.js';
会触发预期错误:
The requested module './greetings.js' does not provide an export named 'default'
奇怪的差异
但实际使用第三方包时,却出现了例外:比如yup可以直接默认导入:
import yup from 'yup';
查看yup的ESM入口文件index.esm.js,发现它没有显式的默认导出,但导入却能正常运行;而同样提供CommonJS模块的rotating-file-stream,尝试默认导入时却会触发上述错误。
测试验证
测试1:yup(版本1.4.0)
import yup from 'yup'; console.log(yup);
→ 正常运行,输出包含yup所有API的对象。
测试2:rotating-file-stream(版本3.2.3)
import rfs from 'rotating-file-stream'; console.log(rfs);
→ 报错,提示模块没有默认导出。
原因解析
1. 包的ESM入口是否做了默认导出兼容
仔细核对yup 1.4.0的index.esm.js会发现,它其实隐含了默认导出逻辑,代码结构大致如下:
// 内部定义完整的yup API对象 const yup = { string: /* ... */, number: /* ... */ }; // 同时导出默认和命名 export default yup; export { yup };
可能你查看时遗漏了默认导出的声明,导致误以为没有默认导出。
而rotating-file-stream的ESM入口仅使用了命名导出,没有设置默认导出:
export function createStream(options) { /* ... */ } // 无 export default 声明
因此用默认导入时,自然会触发“找不到默认导出”的错误。
2. CommonJS模块的ESM导入逻辑差异
如果包的ESM入口确实没有默认导出,但你仍能默认导入,那大概率是因为Node.js在处理CommonJS模块转ESM导入时的特殊逻辑:
- 若CommonJS模块是通过
module.exports = 完整对象导出的(比如yup的CommonJS入口),Node.js会自动将其映射为ESM的默认导出,所以import yup from 'yup'能正常工作。 - 若CommonJS模块是通过
exports.xxx = 函数/变量的命名导出方式(比如rotating-file-stream的CommonJS入口),Node.js不会自动生成默认导出,必须使用import { createStream } from 'rotating-file-stream'这种命名导入方式。
内容的提问来源于stack exchange,提问作者Sina Sharifzade
相关产品推荐
相关产品推荐

