如何修复Google Cloud Build中的TypeScript引用错误?
问题描述
我有一个TypeScript monorepo,其中Vue 3应用从私有模块/包(如@myapp/types或@myapp/config)导入自定义类型和配置常量,这些包不在npm registry中。
本地环境下应用的导入、构建和运行都正常,但在Google Cloud Build中构建失败,报错信息如下:
相关配置文件
依赖消费方(Vue应用)的tsconfig.json
{ "files": [], "compilerOptions": { "forceConsistentCasingInFileNames": true, "strict": true }, "references": [ { "path": "./tsconfig.vite-config.json" }, { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.vitest.json" }, { "path": "../../packages/types/tsconfig.json" }, { "path": "../../packages/config/tsconfig.json" } ] }
tsconfig.app.json
{ "extends": "@vue/tsconfig/tsconfig.web.json", "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], "exclude": ["src/**/__tests__/*"], "compilerOptions": { "allowSyntheticDefaultImports": true, "composite": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@myapp/config": ["../../packages/config"], "@myapp/types": ["../../packages/types"] } } }
Monorepo目录结构
- root(包含tsconfig.base.json)
- apps
- ui <== 依赖消费方(包含tsconfig.app.json + tsconfig.json)
- packages
- types <= 自定义类型模块(包含tsconfig.json)
- config <= 自定义配置模块
- apps
补充配置
types模块的tsconfig.json
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "target": "ESNext", "module": "ES6", "esModuleInterop": true, "skipLibCheck": true, "moduleResolution": "Node", "allowSyntheticDefaultImports": true, "emitDeclarationOnly": true }, "files": ["index.ts"], "display": "Types" }
根目录tsconfig.base.json
{ "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "baseUrl": ".", "forceConsistentCasingInFileNames": true, "strict": true, "composite": true, "declaration": true, "declarationMap": true, "paths": { "@myapp/types": ["./packages/types"], "@myapp/config": ["./packages/config"], "@myapp/ui": ["./packages/ui"], "@myapp/ui-b2b": ["./apps/ui-b2b/src"], "@myapp/ui-partners": ["./apps/ui-patners/src"], "@myapp/api": ["./apps/api/src"] } } }
cloudbuild.yaml
steps: - name: node:16 entrypoint: npm args: ["install"] - name: node:16 dir: "apps/ui-b2b" entrypoint: npm env: - "DEPLOYMENT_TARGET=$_DEPLOYMENT_TARGET" - "VITE_RECAPTCHA_SITE_KEY=$_VITE_RECAPTCHA_SITE_KEY" - "VITE_DYNAMIC_LINKS_DOMAIN=$_VITE_DYNAMIC_LINKS_DOMAIN" - "VITE_API_URL=$_VITE_API_URL" - "VITE_DISPOSABLE_API_KEY=$_VITE_DISPOSABLE_API_KEY" - "VITE_GCP_AUTH_TENANT_ID=$_VITE_GCP_AUTH_TENANT_ID" - "VITE_FIREBASE_CONFIG=$_VITE_FIREBASE_CONFIG" - "VITE_BASE_DOMAIN=$_VITE_BASE_DOMAIN" - "VITE_LOCAL=$_VITE_LOCAL" - "VITE_STRIPE_ALLOW_PROMOTION_CODES=$_VITE_STRIPE_ALLOW_PROMOTION_CODES" - "VITE_TOAST_DURATION=$_VITE_TOAST_DURATION" - "VITE_SEARCH_API_KEY=$_VITE_SEARCH_API_KEY" - "VITE_SEARCH_API_HOST=$_VITE_SEARCH_API_HOST" - "VITE_SEARCH_API_PORT=$_VITE_SEARCH_API_PORT" - "VITE_SEARCH_API_PROTOCOL=$_VITE_SEARCH_API_PROTOCOL" args: ["run", "build:development"] - name: "gcr.io/google.com/cloudsdktool/cloud-sdk" entrypoint: "bash" dir: "apps/ui-b2b" args: [ "-c", "gcloud config set app/cloud_build_timeout 1600 && gcloud app deploy", ] timeout: "1600s"
我尝试过调整路径、移除引用等方法,但都引发了新错误。请问问题原因是什么?如何修复?
问题原因与修复方案
核心原因
- 私有包未预构建:本地环境中TypeScript可能缓存了私有包的编译产物,但Cloud Build是全新环境,直接构建应用时,
@myapp/types和@myapp/config未提前编译,导致TS无法找到对应类型定义或输出文件。 - Vite未同步TS路径映射:TS的
paths配置仅对TS编译器生效,Vite默认不识别该配置,构建时会找不到私有包的实际路径。 - Cloud Build未处理monorepo依赖顺序:当前流程仅安装依赖后直接构建应用,未先编译私有包,导致应用构建时依赖的包无可用输出。
修复步骤
1. 为私有包添加构建脚本并预编译
在packages/types和packages/config的package.json中添加构建命令:
// packages/types/package.json { "scripts": { "build": "tsc" } }
// packages/config/package.json { "scripts": { "build": "tsc" } }
修改cloudbuild.yaml,在安装依赖后添加私有包编译步骤:
steps: - name: node:16 entrypoint: npm args: ["install"] # 编译types私有包 - name: node:16 dir: "packages/types" entrypoint: npm args: ["run", "build"] # 编译config私有包 - name: node:16 dir: "packages/config" entrypoint: npm args: ["run", "build"] # 原有应用构建步骤 - name: node:16 dir: "apps/ui-b2b" entrypoint: npm env: # 保留原有环境变量 args: ["run", "build:development"] # 原有部署步骤
2. 同步Vite路径别名配置
在Vue应用的vite.config.ts中添加resolve.alias,与tsconfig的paths保持一致:
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': path.resolve(__dirname, './src'), '@myapp/config': path.resolve(__dirname, '../../packages/config'), '@myapp/types': path.resolve(__dirname, '../../packages/types') } } })
3. 完善私有包的package.json配置
在packages/types和packages/config的package.json中指定入口字段,让Node和TS能正确识别:
// packages/types/package.json { "name": "@myapp/types", "version": "1.0.0", "main": "./index.js", "types": "./index.d.ts", "scripts": { "build": "tsc" } }
// packages/config/package.json { "name": "@myapp/config", "version": "1.0.0", "main": "./index.js", "types": "./index.d.ts", // 若有类型定义则添加 "scripts": { "build": "tsc" } }
4. 优化TS项目引用构建(可选)
如果使用TS项目引用(references),确保所有私有包的tsconfig中composite: true,然后在根目录package.json添加全量构建脚本:
// 根目录package.json { "scripts": { "build:all": "tsc --build" } }
再修改cloudbuild.yaml的编译步骤为:
- name: node:16 entrypoint: npm args: ["run", "build:all"]
此步骤可替代单独编译每个私有包的操作,一次性构建所有依赖项目。
内容的提问来源于stack exchange,提问作者Stf_F
相关产品推荐
相关产品推荐

