【问题标题】:How can I deploy a GAE service with a local npm dependency?如何部署具有本地 npm 依赖项的 GAE 服务?
【发布时间】:2020-08-02 09:29:10
【问题描述】:

我是 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,那么这种方法就会失败。

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

【问题讨论】:

    标签: node.js google-app-engine npm google-cloud-platform gcloud


    【解决方案1】:

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

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

    【讨论】:

    • 您能否提供一个如何在客户端导入 NPM 包的示例?在服务器端,您只需要它。
    • 对于客户端,我使用Webpack 来捆绑所有依赖项。有大约一百万个关于这个主题的教程。
    • 好的,所以这不是直接导入,比如通过<script src=MY_NPM_PACKAGE>
    【解决方案2】:

    这里的问题是您定义了 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 第一步完成)并分别部署每个服务(注意 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
    

    然后,您可以通过运行 gcloud builds submit --config=cloudbuild-frontend.yamlgcloud builds submit --config=cloudbuild-backend.yaml 来部署一项服务或另一项服务

    【讨论】:

      【解决方案3】:

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

      由于您使用的是 Typescript,您可以简单地使用 Typescript 编译器 tsc,通过在您的 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()。漂亮!

      【讨论】:

        猜你喜欢
        • 2018-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-20
        • 2021-01-14
        • 2019-03-16
        相关资源
        最近更新 更多