无法在ESM项目中使用CommonJS npm包的问题排查
问题原因与解决方案
核心原因:npm link 与常规安装的包处理逻辑差异
Vite 对常规npm安装的第三方包和npm link的本地包采用不同的处理逻辑:
- 从私有仓库安装的包会被Vite自动纳入预构建流程,Vite会把CommonJS格式的代码转译为ESM兼容的格式,所以不会报错。
- 而npm link的包是直接引用本地文件路径,Vite会把它当成项目源码的一部分,不会自动做CommonJS转ESM的处理。当你的React项目(ESM环境)直接导入CommonJS代码时,代码里的
module变量在ESM环境中不存在,就会抛出ReferenceError: module is not defined。
另外你的package.json exports配置里,import字段直接指向了CommonJS的index.js,这在Vite处理link包时会加剧问题——Vite会按ESM规则解析这个文件,自然识别不了CommonJS的module对象。
解决办法
1. 让Vite预构建link的包(最直接)
在项目的vite.config.js中,把你的包名加入optimizeDeps.include列表,强制Vite对它做预构建处理:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], optimizeDeps: { include: ['service-provider'] // 加入你的包名 } });
修改后重启Vite服务,预构建会把CommonJS代码转成ESM兼容格式,报错就会消失。
2. 临时调整包的导出逻辑(可选)
如果不想改Vite配置,可以在你的包的index.js里加一层兼容判断,同时支持CommonJS和ESM:
'use strict'; const service = require('./source'); if (typeof module !== 'undefined') { module.exports = service; } if (typeof exports !== 'undefined') { Object.assign(exports, service); } if (typeof define === 'function' && define.amd) { define(() => service); } if (typeof window !== 'undefined') { window.RoutingService = service.RoutingService; }
不过这个方法只是临时兼容,不如第一种方法彻底。
3. 检查package.json的exports配置(优化建议)
虽然你不想用双模块策略,但可以调整exports配置,明确告诉Node/Vite该如何处理不同导入方式:
"exports": { ".": { "require": "./index.js", "import": "./index.js", "default": "./index.js" } },
同时确保type: "commonjs"保留,这样常规安装的包依然能正常工作,link的包配合Vite预构建也没问题。
内容的提问来源于stack exchange,提问作者dhruvin vaghasiya
相关产品推荐
相关产品推荐

