You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何module.exports=require(...)直接赋值可行,经临时变量赋值却报错?

CommonJS与ES模块互操作的特殊赋值机制问题

问题场景

项目结构:

.
├── dep
│   ├── a.mjs
│   ├── b.js
│   └── c.js
└── entry.mjs

代码内容:
entry.mjs:

import { foo } from "./dep/a.mjs";
console.log(foo);

dep/a.mjs:

export * from './b.js'

dep/b.js(有效写法):

module.exports = require("./c.js"); // 💯

dep/b.js(无效写法):

// 为何此写法不生效 ❌
// const m = require("./c.js"); 
// module.exports = m;

dep/c.js:

exports.foo = "foo";

运行node entry.mjs时,有效写法能正常输出foo,无效写法会抛出解构错误。

原因解析

这是Node.js处理ES模块与CommonJS模块互操作时的特殊逻辑:

  • 当CommonJS模块直接执行module.exports = require(...)时,Node.js会识别出这是将另一个模块的导出对象直接赋值给当前模块的导出,此时在ES模块用export * from导入该CommonJS模块时,Node.js会自动展开目标模块的导出成员,让ES模块能正确解构出foo这类具体导出。
  • 而通过临时变量中转时,Node.js无法识别这个赋值的来源是另一个模块的导出,会将当前CommonJS模块的module.exports视为普通对象,ES模块的export * from无法从普通CommonJS模块对象中解析出命名导出,因此解构foo时会报错。

相关文档参考

Node.js官方文档中关于ES模块与CommonJS互操作的章节明确说明:ES模块导入CommonJS模块时,默认会将其视为只有默认导出的模块,但针对export * from处理CommonJS模块有特殊兼容逻辑——仅当CommonJS模块的module.exports直接引用另一个模块的导出(即module.exports = require(...)形式)时,才能被ES模块识别并展开命名导出。

Vue3源码中的应用

Vue3源码中大量采用这种写法,是为了在混合使用ES模块和CommonJS模块的场景下,确保跨模块的导出能在Node.js环境或各类构建工具中被正确解析,避免互操作时的导出丢失问题。

内容的提问来源于stack exchange,提问作者bigboss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 17:35:44