如何部署具有本地 npm 依赖项的 GAE 服务?

How can I deploy a GAE service with a local npm dependency?

我是 Google Cloud 的新手,似乎无法弄清楚如何部署具有同级本地依赖项的 Google App Engine 服务。我有一个这样的项目结构(我的堆栈是 TypeScript、nestJS、React):

-frontend
    app.yaml
    package.json
-backend
    app.yaml
    package.json
-common
    package.json
dispatch.yaml

frontend包将静态代码部署到default服务,backend包部署到api服务。 common 包包含一些我想在前端和后端之间共享的代码。他们将其包含在 package.json 文件中,如下所示:

dependencies: {
    common: "file:../common"
}

此结构在本地运行良好。问题是当我部署后端时,npm install 失败,因为它找不到 common 包。这是有道理的,因为我知道它只会将 backend 的内容上传到该服务。但是实现这一目标的正确方法是什么?

我想我可以只部署一个包含所有代码的服务,并让我的顶级 package.json 委托 npm start 到后端的 package.json。但这只有效,因为我的前端是完全静态的,所以我只有一个包需要 npm start 才能被调用。似乎应该有更好的方法来处理这个问题,因为如果我有两个单独的后端,每个后端都需要自己的 npm start.

,那么这种方法就会失效

我猜我正在以一种根本错误的方式思考这件事的某些方面,但我需要帮助来弄清楚那是什么。

我不熟悉 GAE,但我共享代码的解决方案是将共享代码打包为 NPM 包并将其导入服务器和客户端应用程序

如果您选择不制作共享包 public,您仍然可以直接从 git 存储库安装。请注意,这可能会使您的部署复杂化,因为您必须配置 SSH 密钥以允许克隆您的私有存储库。

这里的事情是你定义了 2 个 App Engine 服务,frontendbackend,它们将被独立打包并安装在不同的实例上,它们永远不会共存于一个单一的实例。所以两者都需要包含通用包。

当您 运行 gcloud app deploy 时,包含该服务的 app.yaml 文件的文件夹被视为根文件夹,树中的文件和文件夹不会被部署,正如你提到的。

我理解,从开发的角度来看,两个服务共享一个公共包是有意义的,因为它避免了重复代码。管理此问题的一种方法是使用 Cloud Build 创建一个构建管道,该管道将处理将此公共代码合并到两个服务中并分别部署它们。例如,像这样:

steps:
- name: ubuntu
  id: 'copy-file'
  args:
  - '-c'
  - |
        cp ./common/package.json frontend/ && cp ./common/package.json backend/
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['app', 'deploy']
  dir: 'frontend/'
  timeout: '1600s'
  waitFor: ['copy-file']
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['app', 'deploy']
  dir: 'backend/'
  timeout: '1600s'
  waitFor: ['copy-file']

第一步会将公共包复制到两个目录(您需要更新 package.json 中的公共依赖路径,因为它现在位于同一目录中)。接下来的 2 个步骤将 运行 并行(两个 wait for the first step to finish) and deploy each service separately (note the dir 参数)。

然后您可以通过 运行 在根目录中执行以下命令来部署您的服务:

gcloud builds submit

请注意,这将始终部署这两个服务。

如果您希望能够部署一项服务而不是另一项服务,您可以像这样定义 2 个 cloudbuilds 文件:

cloudbuild-frontend.yaml:

steps:
- name: ubuntu
  args:
  - '-c'
  - |
        cp ./common/package.json frontend/
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['app', 'deploy']
  dir: 'frontend/'
  timeout: '1600s'

cloudbuild-backend.yaml:

steps:
- name: ubuntu
  args:
  - '-c'
  - |
        cp ./common/package.json backend/
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['app', 'deploy']
  dir: 'backend/'
  timeout: '1600s'

你最终会得到这样一棵树:

-frontend
    app.yaml
    package.json
-backend
    app.yaml
    package.json
-common
    package.json
cloudbuild-frontend.yaml
cloudbuild-backend.yaml
dispatch.yaml

然后您可以通过 运行ning gcloud builds submit --config=cloudbuild-frontend.yamlgcloud builds submit --config=cloudbuild-backend.yaml

部署一项或多项服务

我在使用 Firebase 时遇到过类似的情况,我有代码想在前端和后端之间共享,而不必在两个地方维护更改。

由于您使用的是 Typescript,因此您可以简单地使用 tsc,Typescript 编译器,通过在 tsconfig.json 文件。 https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

对于前端,您可以将其输出为 .js 文件,然后将其加载为 <script src='myCommonFile.js>。在后面,你会 requireimport 它。

那么诀窍就是编写代码,使其可以在浏览器和节点环境中使用。引用 this SO post 中的代码:

(function(exports){

    // Your code goes here. For example: 
   exports.test = function(){
        return 'hello world'
    };

})(typeof exports === 'undefined'? this.mymodule = {} : exports);

因此,如果 exports 未定义,您必须在浏览器中,在这种情况下 mymodule 声明在 window 上(即 this)。或者,如果定义了 exports,则它处于 node 上下文中,在这种情况下,您可以只使用 var mymodule = require('mymodule')。在任一环境中,您都可以将其用作 mymodule.test()。漂亮!