部署继承根tsconfig.json的Node.js Google Cloud Function遇构建错误求助
问题背景
我通过CI工具执行以下命令部署Google Cloud Function:
gcloud functions deploy testFunction --region europe-west1 --trigger-http --runtime nodejs16 --source ./testFunction --set-env-vars ...
项目目录结构如下:
. ├── testFunction │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json └── tsconfig.json
子目录的tsconfig.json继承根目录配置:
// /testFunction/tsconfig.json { "extends": "../tsconfig.json", "include": ["./src"], "compilerOptions": { "outDir": "./build", "rootDir": "./src", "tsBuildInfoFile": "buildcache.tsbuildinfo" } }
近两日构建突然报错,提示找不到根目录的tsconfig.json。下载谷歌端上传的源码后发现,只有testFunction目录被上传。之前相同配置能正常运行,怀疑是Google Cloud Build的行为发生了变更。
已尝试两个临时方案,但都不够优雅:
- 复制根目录
tsconfig.json内容到子目录,取消继承 - 用
ln -s ../tsconfig.json parent.tsconfig.json创建软链接,修改子配置继承该链接文件
需要解决两个问题:
- 为什么会突然出现这个变化?
- 有没有更优雅的解决方案?
原因分析
Google Cloud Functions部署时,--source参数指定的目录是构建上下文,官方设计逻辑是仅上传该目录内的文件到构建环境,不会包含父目录内容。之前能正常运行应该是因为构建逻辑存在宽松处理或缓存机制,偶然允许了跨目录读取,但这属于非预期行为。近期Google Cloud Build可能收紧了构建上下文的边界,严格遵循设计规范,导致跨目录的配置继承失效。
更优解决方案
方案1:调整构建上下文为根目录,用.gcloudignore精简上传内容
把部署的构建上下文设为项目根目录,同时通过.gcloudignore排除无关文件,只保留需要的内容:
- 修改部署命令:
gcloud functions deploy testFunction --region europe-west1 --trigger-http --runtime nodejs16 --source ./ --set-env-vars ...
- 在根目录创建
.gcloudignore文件,配置如下:
# .gcloudignore # 先排除所有文件 * # 保留根目录的tsconfig.json !tsconfig.json # 保留testFunction目录 !testFunction/
- 确保
testFunction/package.json的main字段指向编译后的入口文件(比如build/index.js),适配云端构建后的执行路径。
这样构建时会上传根目录的tsconfig.json和testFunction目录,子配置的"extends": "../tsconfig.json"就能正常读取。
方案2:本地/CI预编译,部署编译后的产物
在testFunction的package.json中添加编译脚本,先在本地或CI环境完成TypeScript编译(此时能正常读取根目录的配置),再部署编译好的产物:
- 修改
testFunction/package.json的scripts:
{ "scripts": { "build": "tsc", "deploy": "npm run build && gcloud functions deploy testFunction --region europe-west1 --trigger-http --runtime nodejs16 --source ./testFunction/build --set-env-vars ..." } }
- 在CI环境执行
npm run deploy,先完成本地编译,再上传编译后的JS文件到云端,彻底避免云端构建时的跨目录依赖问题。
关于行为变更的说明
最可能的原因是Google Cloud Build修复了之前的非预期行为,严格遵循了"构建环境仅能访问指定--source目录内文件"的设计规范。之前的正常运行属于偶然情况,现在的行为才是符合官方部署逻辑的。
内容的提问来源于stack exchange,提问作者user2625636

