Vite可通过插件机制模拟虚拟模块,利用resolveId和load钩子拦截路径并动态生成TS代码,配合tsconfig.json的paths和include配置实现类型支持与IDE识别。

Vite 本身不直接提供“虚拟模块”概念,但可通过插件机制(尤其是 resolveId + load 钩子)模拟虚拟模块行为,配合 TypeScript 实现动态代码生成。关键在于:让 Vite 在请求某个路径时,不读取真实文件,而是由插件动态生成 TS 代码并返回,再交由 TypeScript 编译器处理。
以下为可落地的配置方式,适用于 Vue/React/Solid 等主流框架项目:
✅ 虚拟模块的核心实现逻辑
Vite 插件通过拦截模块请求路径(如 virtual:config),在 resolveId 中识别虚拟前缀,在 load 中返回生成的 TypeScript 字符串。TS 类型检查仍依赖 tsconfig.json 的 include 和 paths 配置,确保 IDE 和 tsc --noEmit 能识别该模块。
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
export default defineConfig({
plugins: [
{
name: 'vite-plugin-virtual-module',
resolveId(id) {
if (id.startsWith('virtual:')) {
return id // 告诉 Vite 这是个需拦截的虚拟路径
}
},
load(id) {
if (id === 'virtual:api-config') {
// 动态生成 TS 模块内容(例如从环境变量或 JSON 文件推导)
const config = {
baseUrl: process.env.API_BASE_URL || 'https://api.example.com',
timeout: 10000,
}
return `
export const API_CONFIG = ${JSON.stringify(config, null, 2)} as const;
export type ApiConfig = typeof API_CONFIG;
`
}
if (id === 'virtual:feature-flags') {
const flags = { enableDarkMode: true, showBetaBanner: false }
return `
export const FEATURES = ${JSON.stringify(flags)} as const;
export type FeatureFlags = typeof FEATURES;
`
}
}
}
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
})✅ TypeScript 必须同步适配(否则类型报错)
仅靠 Vite 插件返回代码还不够,TS 编译器和编辑器(VS Code)需要知道这些虚拟模块存在且可导入。需在 tsconfig.json 中显式声明:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"virtual:*": ["src/virtual/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
]
}⚠️ 注意:"virtual:*" 是逻辑路径映射,实际无需创建 src/virtual/ 目录。它只是告诉 TS “当看到 import { ... } from 'virtual:xxx' 时,请当作合法模块处理”。
✅ 在代码中安全使用虚拟模块
// src/composables/useApi.ts
import { API_CONFIG } from 'virtual:api-config' // ✅ TS 识别类型,IDE 有提示
import { FEATURES } from 'virtual:feature-flags'
console.log(API_CONFIG.baseUrl) // 类型安全:string
console.log(FEATURES.enableDarkMode) // 类型安全:boolean✅ 进阶建议:配合 @rollup/plugin-dynamic-import-vars 或 glob 生成模块列表
若需根据目录结构自动生成虚拟模块(例如扫描 src/api/endpoints/ 下所有 .ts 文件并汇总成一个 virtual:endpoints),可在 load 钩子中读取文件系统,用 fs.readdirSync + require.resolve 构建导出列表,再拼接为 TS 字符串返回。
TypeScript 不会编译虚拟模块本身(因无物理文件),但 Vite 的 load 返回内容会被当作真实 .ts 源码送入 TS 类型检查流程——只要 tsconfig.json 正确声明路径,就能享受完整类型推导、跳转、重构支持。


















