如何使用gcloud app deploy将NX工作区单应用部署至Google AppEngine
问题背景
我有一个包含多个应用的NX仓库,所有应用都能在本地正常构建和启动。现在想把这些应用部署到Google AppEngine,后续计划用GitHub Actions自动化部署,现阶段先尝试从本地用gcloud app deploy app.yaml --quiet命令部署。在非NX仓库里能轻松完成,但在NX工作区内遇到了部署方法的问题。
我试过两种部署方式:
- 通过NX项目目标从apps文件夹部署(比如
nx run api-one:deploy) - 通过npm目标从仓库根目录部署(比如
npm run deploy:api-two)
报错信息
NX项目目标部署(
nx run api-one:deploy):
访问部署后的应用显示Service Unavailable,日志提示Cannot find package 'express' imported from /workspace/dist/main.js。npm目标部署(
npm run deploy:api-two):
访问部署后的应用显示Service Unavailable,日志提示找不到/workspace/dist/apps/api-two/main.js。
核心问题
如何用gcloud app deploy ...命令将NX工作区中的单个应用正确部署到Google AppEngine?
代码示例
仓库结构:
nx-workspace ├── apps │ ├── api-one │ │ ├── src │ │ │ ├── main.ts │ │ │ └── ... │ │ ├── package.json │ │ ├── project.json │ │ ├── app.yaml │ │ └── .... │ └── api-two │ ├── src │ │ ├── main.ts │ │ └── ... │ ├── package.json │ ├── project.json │ ├── app.yaml │ └── .... ├── dist │ └── apps │ ├── api-one │ │ ├── main.js │ │ └── ... │ └── api-two │ ├── main.js │ └── ... ├── package.json └── ...
api-one package.json
{ "name": "api-one", "version": "0.0.1", "type": "module", "scripts": { "start": "node ./dist/apps/api-one/main.js", "gcp-build": "" } }
api-one project.json
... "build": { "executor": "@nx/esbuild:esbuild", "options": { "main": "apps/api-one/src/main.ts", "tsConfig": "apps/api-one/tsconfig.app.json", "outputPath": "dist/apps/api-one" }, "configurations": { "prod": { "optimization": false, "generatePackageJson": true, "extractLicenses": true, "inspect": false } } }, "deploy": { "executor": "nx:run-commands", "dependsOn": [ "^build:prod" ], "defaultConfiguration": "dev", "options": { "cwd": "apps/api-one", "parallel": false }, "configurations": { "dev": { "command": "gcloud app deploy app.yaml --quiet" } } }, ...
api-one app.yaml
runtime: nodejs18 instance_class: F1 handlers: - url: /static static_dir: public/static expiration: 30d - url: /.* secure: always redirect_http_response_code: 301 script: auto
root package.json
... "scripts": { "start": "node ./dist/apps/api-two/main.js", "gcp-build": "", "deploy:app-one": "gcloud app deploy ./apps/api-two/app.yaml --quiet" }, ...
解决方案
问题根源分析
NX项目目标部署失败原因:
- 部署时工作目录设为
apps/api-one,GAE会上传该目录的内容,但编译后的代码在根目录的dist/apps/api-one下,导致GAE无法找到正确的启动文件。 apps/api-one/package.json中没有依赖(依赖由NX构建时生成在dist/apps/api-one/package.json),且启动脚本路径指向本地的dist目录,在GAE环境中无效。
- 部署时工作目录设为
npm根目录部署失败原因:
- 部署上下文为仓库根目录,GAE会上传根目录内容,但默认可能忽略
dist目录(若存在.gcloudignore配置),或者启动脚本依赖根目录的package.json,而该文件未包含应用的完整依赖。
- 部署上下文为仓库根目录,GAE会上传根目录内容,但默认可能忽略
修复步骤
1. 调整应用的package.json启动脚本
修改apps/api-one/package.json的start脚本,使其适配dist目录的结构:
{ "name": "api-one", "version": "0.0.1", "type": "module", "scripts": { "start": "node main.js", // 改为当前目录的main.js "gcp-build": "" } }
NX构建时会自动将这个脚本同步到dist/apps/api-one/package.json中。
2. 修改NX项目的deploy目标
更新api-one/project.json中的deploy配置,将部署工作目录切换到编译后的dist/apps/api-one,并提前复制app.yaml到该目录:
... "deploy": { "executor": "nx:run-commands", "dependsOn": [ "build:prod" ], "defaultConfiguration": "dev", "options": { "cwd": "dist/apps/api-one", "parallel": false }, "configurations": { "dev": { "command": "cp ../../apps/api-one/app.yaml . && gcloud app deploy app.yaml --quiet" } } }, ...
dependsOn改为build:prod(不需要^前缀,因为只需要当前应用的构建产物)cwd设置为dist/apps/api-one,确保部署上下文是编译后的应用目录- 命令中先复制
app.yaml到dist目录,再执行部署
3. 调整根目录npm部署脚本
修改root/package.json中的deploy:app-one脚本,确保先构建应用、复制配置文件,再切换到dist目录部署:
... "scripts": { "start": "node ./dist/apps/api-two/main.js", "gcp-build": "", "deploy:api-one": "nx build api-one --prod && cp apps/api-one/app.yaml dist/apps/api-one && cd dist/apps/api-one && gcloud app deploy app.yaml --quiet", "deploy:api-two": "nx build api-two --prod && cp apps/api-two/app.yaml dist/apps/api-two && cd dist/apps/api-two && gcloud app deploy app.yaml --quiet" }, ...
4. 检查.gcloudignore配置
确保根目录的.gcloudignore文件没有排除dist目录,若存在该文件,删除或注释掉dist/相关规则:
# .gcloudignore示例(确保不包含dist) node_modules/ .git/ .nx/
验证部署
执行以下命令测试部署:
- 通过NX目标部署:
nx run api-one:deploy - 通过npm脚本部署:
npm run deploy:api-one
部署完成后,访问应用URL,即可正常运行。
内容的提问来源于stack exchange,提问作者BSimpson

