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

Vitest加载依赖CJS导出而非ESM的原因及强制ESM方案

问题原因与解决方案

原因分析

Vite和Vitest的模块解析逻辑存在差异,导致二者选择了不同的包导出:

  • Vite的行为:作为前端构建工具,Vite遵循前端生态的通用规则,优先读取package.json中的module字段,该字段专门用于指定ESM格式的入口文件,因此会自动加载dist/esm/index.js。
  • Vitest的行为:Vitest的运行时更贴近Node.js的模块解析逻辑,但对于未定义exports字段的旧版package.json,它的默认解析策略会优先读取main字段。同时,第三方包的CJS导出文件使用.js后缀,且自身package.json未设置"type": "commonjs",这会让Vitest在ESM环境(消费应用"type": "module")下产生解析混淆,最终选择了main指向的CJS代码。

强制Vitest使用ESM导出的方案

方案1:规范第三方包的exports字段(推荐)

如果有权限修改第三方包的package.json,添加exports字段是最标准的解决方式,Node.js和现代测试工具都会严格遵循条件导出规则:

"exports": {
  ".": {
    "import": "./dist/esm/index.js",
    "require": "./dist/cjs/index.js",
    "types": "./dist/types/index.d.ts"
  }
}

配置后,ESM环境下会自动加载import对应的路径,CJS环境则加载require路径,彻底避免解析歧义。

方案2:修改Vitest的解析优先级

在消费应用的vitest.config.js中,配置resolve.mainFields,让Vitest优先读取module字段:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    resolve: {
      mainFields: ['module', 'main']
    }
  }
})

方案3:添加包别名(临时应急)

如果只是临时测试需求,可以给目标包添加别名,直接指向ESM入口:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  resolve: {
    alias: {
      'your-package-name': 'your-package-name/dist/esm/index.js'
    }
  }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:46:24