如何在Monorepo中实现两个打包TS包间的跨包导入
Monorepo前端导入后端共享类型/枚举的解决方案
问题背景
我有一个包含/frontend和/backend目录的Monorepo,后端存在需要导入到前端的共享类型与枚举。已在前端tsconfig.json配置路径别名并添加项目引用,前端导入语句如下:
import { isUser } from '@backend/models/account'
运行tsc时触发大量TS6305错误:
src/state/globalState.ts:7:8 - error TS6305: Output file 'C:/Users/user/Desktop/monorepoName/backend/models/account.d.ts' has not been built from source file 'C:/Users/user/Desktop/monorepoName/backend/models/account.ts'.
后端使用moduleResolution: bundler和vite-node,无构建步骤,且因部署限制无法使用需编译的共享包方案。
前端tsconfig.json配置:
{ "compilerOptions": { "rootDir": "./", "target": "ES2020", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "paths": { "@/*": ["./src/*"], "@backend/*": ["../backend/*"], // "@shared/*": ["../shared/*"], "$/*": ["./react-maptiler/*"], "react-maptiler": ["./react-maptiler/index.ts"] }, "typeRoots": ["./src/types"] }, "exclude": ["node_modules", "dist"], "include": ["src", "serviceWorker/generateSW.js", "serviceWorker/sw.js"], "references": [ { "path": "./tsconfig.node.json" }, { "path": "../backend/" }, { "path": "../shared/" } ] }
后端tsconfig.json配置:
{ "compilerOptions": { /* "incremental": true, */ "composite": true, "target": "ESNext", "experimentalDecorators": true, /* This is essential for DBOS to work: */ "emitDecoratorMetadata": true, "module": "ESNext", "moduleResolution": "bundler", // "declaration": true, // "declarationMap": true, "sourceMap": true, // "outDir": "./dist", "newLine": "lf", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "paths": { "@/*": ["./*"] //"@shared/*": ["../shared/*"] }, "baseUrl": ".", "resolveJsonModule": true, "typeRoots": ["@types"] }, "include": [ "api", "auth", "drizzle", "models", "utils", "types", "test/test.ts", "auth/firebase.ts", "zipcodes", "services", "config", "lib", "test", "@types", "shared" ], "exclude": ["dist"] // "references": [{ "path": "../shared/" }] }
可行解决方案
方案1:类型专用导入+取消项目引用(最简方案)
仅需后端类型/枚举时,直接用类型导入语法,跳过TS对后端源码的构建检查:
- 修改前端导入语句,添加
type关键字:
import type { isUser, UserRole } from '@backend/models/account'
- 调整前端
tsconfig.json:- 移除
references数组中的"../backend/"和"../shared/"项 - 保留
skipLibCheck: true,确保TS跳过对非前端代码的类型检查
- 移除
方案2:后端仅生成类型声明文件
无需全量编译后端,仅生成.d.ts类型文件供前端使用:
- 修改后端
tsconfig.json:- 取消注释
"declaration": true,开启类型声明生成 - 添加
"declarationDir": "./types",将类型文件统一输出到后端types目录 - 保留
composite: true配置
修改后关键配置片段:
- 取消注释
{ "compilerOptions": { "composite": true, "declaration": true, "declarationDir": "./types", // 其余原有配置不变 } }
- 运行后端类型生成命令:
tsc --emitDeclarationOnly
此命令仅生成类型文件,不会编译JS代码,不影响后端运行。
3. 调整前端tsconfig.json的路径别名:
"paths": { "@backend/*": ["../backend/types/*"], // 其余别名不变 }
方案3:Vite别名+TS类型映射(Vite项目专属)
如果前端基于Vite构建,利用Vite的路径解析能力绕过TS项目引用限制:
- 在前端
vite.config.ts中添加别名:
import { defineConfig } from 'vite' import path from 'path' export default defineConfig({ resolve: { alias: { '@backend': path.resolve(__dirname, '../backend'), }, }, })
- 调整前端
tsconfig.json:- 移除
references中的后端项目引用 - 确保
paths中的@backend别名与Vite配置一致 - 在
include中仅添加需要的后端类型文件路径(避免全量引入后端代码):
- 移除
"include": [ "src", "../backend/models/**/*.ts", "../backend/types/**/*.ts", // 其余原有include项不变 ]
内容的提问来源于stack exchange,提问作者GMoney
相关产品推荐
相关产品推荐

