Vitest vmThreads 导入 ESM JSON 报 ERR_VM_MODULE_DIFFERENT_CONTEXT
测试文件未加载就失败,真正触发点可能是外置 ESM 依赖内部的 JSON import。可对确认的包局部 inline,或评估非 VM pool。
测试文件还没进入断言,就报 Linked modules must use the same context,序列化错误码为 ERR_VM_MODULE_DIFFERENT_CONTEXT。如果只有 vmThreads 失败,forks、threads 能运行,检查外置 ESM 依赖内部是否导入了 JSON。
明确触发组合是 Vitest 3.2.7、Vite 7.3.6、Node 22.23.3。外置 ESM 本身未必有问题:同样的包去掉 JSON import 后可以链接;加入 import data from './data.json' with { type: 'json' } 才触发跨 VM context 的错误。
报错文件未必是带入 JSON 的包
保留完整错误、pool、实际安装版本和依赖入口。测试文件只是导入失败的边界,不能看到它的文件名就断定测试代码用了多个 vm 实例。
检查失败依赖是否真的作为 external 执行。工作区 file: 链接包可能被当源码内联,而安装到 node_modules 的发布包或归档包走另一条路径;用链接包做对照正常,不能推翻外置包的故障。
在受影响实现中,外置 ESM 模块使用测试自己的 VM context,JSON 模块却可能进入另一个 context,两者不能直接链接。它与 JSON 内容不合法或缺少 import attribute 不同:后两者有自己的语法与类型错误,不应套用本处理。
对确认的 ESM 包局部 inline
短期需保留 Vitest 3.2.7 时,可把真正持有 JSON import 的包加入原配置:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
pool: 'vmThreads',
server: {
deps: {
inline: ['esm-json-dep'],
},
},
},
});
esm-json-dep 是示例,替换为实际失败包。保留现有环境、setup 和其他依赖规则;如果 JSON import 在更深的外置包中,继续按实际依赖图核对。不要直接设 inline: true 来绕过全部边界,那会扩大转换范围。
deps.optimizer.ssr.include 不等于 server.deps.inline。预构建不保证输出一定按测试 VM 内联执行,所以不能把“优化器已包含包”当成跨 context 已消除。
另一条选择是评估切到 forks 或普通 threads。它会改变隔离和运行资源模型,需覆盖原有测试环境与原生依赖;不能只为了一个文件切换后,就认定整套测试仍等价。
检查测试真的被收集并执行
沿原失败文件验证 JSON 导出的数据能被读取,断言数量符合预期,原有 mock 和清理仍运行。再运行相关测试组,防止只有控制文件成功而原文件仍未加载。
Vitest 3.2 线不应被当成仍接收所有新修复的版本;升级到后续主版本需核对迁移与 Node 支持,不能凭一个关闭状态推断旧版已修。保存原锁文件和局部 inline 配置,升级后先用外置 ESM 加 JSON 的原组合回归,再决定是否移除绕行。


