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

从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包的配置:

  1. 更新tsconfig.json的模块设置:
    {
      "compilerOptions": {
        // 保留其他配置
        "module": "ESNext",
        "moduleResolution": "bundler",
        "target": "ESNext" // 可选,提升ESM兼容性
      }
    }
    
  2. 在本地包的package.json中添加"type": "module",明确标识为ESM模块:
    {
      // 保留其他配置
      "type": "module",
      "exports": {
        ".": "./build/index.js"
      }
    }
    
  3. 若需兼容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环境不匹配,导致类型检查未报错。

修复步骤:

  1. 确保本地包的类型声明与模块格式一致:若改为ESM模块,重新编译后生成的.d.ts会正确标记为ESM,VS Code会自动检测导入问题。
  2. 更新Vite项目的tsconfig.json,匹配Vite的模块解析逻辑:
    {
      "compilerOptions": {
        // 保留其他配置
        "moduleResolution": "bundler",
        "isolatedModules": true
      }
    }
    
  3. 重启VS Code的TypeScript服务:按下Ctrl+Shift+P(Windows)或Cmd+Shift+P(Mac),选择TypeScript: Restart TS Server,让配置生效。

内容的提问来源于stack exchange,提问作者Bram Vanbilsen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:09:26