从CRA迁移到Vite后本地模块导出无法识别的问题
本地Node.js包在Vite中导入失败的问题及解决
问题背景
此前使用CRA(Webpack默认配置)时,导入本地Node.js包的导出成员完全正常,但切换到Vite后出现以下报错:
Uncaught SyntaxError: The requested module '/@fs/Users/...{long_path}.../lib/shared/countries/build/index.js' does not provide an export named 'countryListAllIsoData'
Vite项目通过npm create vite@latest创建,采用TypeScript、React、SWC预设。仅本地包(非npm registry安装的包)出现导入失败,问题锁定在本地配置,但尚未定位具体原因。
核心问题
问题1:如何让导入正常工作?为何Webpack下正常、Vite中失效?
Vite要求项目package.json设置"type": "module",这种模块导入方式是否破坏了现有代码?
问题2:如何让代码检查工具(linter)提前显示这些错误?
使用VS Code时,编辑器对当前导入方式无报错,且可正常跳转至导出定义,导致误以为导出配置正确。
相关代码与配置
项目中的导入方式
import { countryListAllIsoData } from "countries";
项目的tsconfig.json和package.json仅新增依赖,其余与Vite初始化文件一致。
本地包countries的package.json
{ "name": "countries", "version": "1.0.0", "description": "", "main": "./build/index.js", "exports": { ".": "./build/index.js" }, "scripts": { "build": "tsc", "prepare": "npm run build" }, "keywords": [], "author": "Bram Vanbilsen", "license": "UNLICENSED", "devDependencies": { "typescript": "^4.8.4" } }
本地包的tsconfig.json
{ "compilerOptions": { "target": "es2016", "module": "commonjs", "moduleResolution": "nodenext", "declaration": true, "declarationMap": true, "outDir": "./build", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
本地包的index.ts
export const countryListAllIsoData = [...] as const;
解决方案
针对问题1:修复Vite导入失败
问题本质是本地包编译为CommonJS模块,但Vite作为ESM优先的构建工具,处理CommonJS与ESM互操作的逻辑和Webpack不同:
- Webpack会自动抹平CommonJS与ESM的差异,即使你用ESM语法解构CommonJS的命名导出,也能正常运行;
- Vite在原生ESM环境下运行,默认将CommonJS模块视为单个
default导出,无法直接解构命名导出(除非开启兼容配置)。
方案1:将本地包改为编译为ESM模块
修改countries包的配置:
- 更新
tsconfig.json的模块设置:{ "compilerOptions": { // 保留其他配置 "module": "ESNext", "moduleResolution": "bundler", "target": "ESNext" // 可选,提升ESM兼容性 } } - 在本地包的
package.json中添加"type": "module",明确标识为ESM模块:{ // 保留其他配置 "type": "module", "exports": { ".": "./build/index.js" } } - 若需兼容CommonJS环境,可添加条件导出:
{ "exports": { ".": { "import": "./build/index.js", "require": "./build/index.cjs" } }, "scripts": { "build": "tsc && tsc --module CommonJS --outDir build-cjs", "prepare": "npm run build" } }
方案2:不修改本地包,配置Vite兼容CommonJS
在Vite项目的vite.config.ts中添加以下配置,让Vite正确处理CommonJS模块的命名导出:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; export default defineConfig({ plugins: [react()], optimizeDeps: { esbuildOptions: { mainFields: ['module', 'main'], resolveExtensions: ['.js', '.jsx', '.ts', '.tsx', '.cjs'] } }, // 可选:解决本地路径权限问题 server: { fs: { strict: false } } });
针对问题2:让VS Code检测导入错误
VS Code的TypeScript语言服务依赖tsconfig.json配置,当前因为本地包的.d.ts基于CommonJS生成,与Vite项目的ESM环境不匹配,导致类型检查未报错。
修复步骤:
- 确保本地包的类型声明与模块格式一致:若改为ESM模块,重新编译后生成的
.d.ts会正确标记为ESM,VS Code会自动检测导入问题。 - 更新Vite项目的
tsconfig.json,匹配Vite的模块解析逻辑:{ "compilerOptions": { // 保留其他配置 "moduleResolution": "bundler", "isolatedModules": true } } - 重启VS Code的TypeScript服务:按下
Ctrl+Shift+P(Windows)或Cmd+Shift+P(Mac),选择TypeScript: Restart TS Server,让配置生效。
内容的提问来源于stack exchange,提问作者Bram Vanbilsen
相关产品推荐
相关产品推荐

