科技 · 实用指南
Node 报 ERR_REQUIRE_ESM?改模块设置前先追踪运行时调用方
源码可能写着 import,但编译后的 JavaScript、某个依赖或测试运行器仍在调用 require()。先证明运行时边界,再选择完整迁移 ESM、动态 import 桥接或经过评审的临时版本固定。

ERR_REQUIRE_ESM 指向运行时的模块格式边界。Node 实际执行的行不一定是你写下的行:TypeScript、Babel、Vite、Electron、Jest 或传递依赖都可能生成或调用 require()。
先保留第一份完整堆栈,记录精确 Node 版本,并检查实际执行的 JavaScript,再改 package.json。修复取决于谁拥有 CommonJS 调用方,以及目标 ESM 图能否同步加载。
先冻结运行时证据
保存完整堆栈、命令、工作目录、Node 与包管理器版本及 lockfile 修订。标出目标 ESM 文件和 Node 内部之外的首个调用方。
不要先删 node_modules 或 lockfile;那会改变依赖图并抹掉原始失败边界。
检查真正执行的文件
打开堆栈中的调用方。如果它位于 dist、out、build 或 Electron bundle,确认输出行是否仍是 require()。
TypeScript 项目记录 module、moduleResolution、调用方扩展名及最近 package.json 的 type。node16、node18、nodenext 才会按文件模拟 Node 行为。
映射包边界和依赖所有者
用 lockfile 与依赖树确认精确包版本,并判断 CommonJS 调用属于你的代码、直接依赖还是传递依赖;读取该包的 exports 与 type。
同时记录 Node 版本。特定版本解析回归或包含顶层 await 的图,与普通 ESM-only 升级不是同一修法。
只选择一条修复路径
能一致迁移时,同时调整包边界、编译输出、相对扩展名与运行入口,并测试所有入口。必须保留 CommonJS 时,只在可异步化的自有边界使用动态 import。
调用位于依赖内时优先升级到支持当前运行时的上游版本。临时固定旧版必须记录原因、安全暴露与移除日期。
在同一边界验证
清空旧输出后重建,但不要意外重写 lockfile。确认执行文件不再用 require 调 ESM-only 目标,或桥接返回了正确导出。
用同一 Node 版本运行原命令、测试与生产入口;保存最终依赖树和输出片段。
