整理多项函数


在将 Cloud Functions 集成到项目中时,您的代码可能会扩展以容纳许多独立的函数。一个文件中可能无法合理地容纳过多的函数,或者不同的团队可能会部署不同的函数组,从而导致一个团队可能会覆盖或意外删除另一个团队的函数。Cloud Functions 提供了多种整理代码的方法,可让您更轻松地浏览和维护函数。

整理代码库中的函数

您可以使用 firebase.json 中的函数配置对象的 codebase 属性,在多个代码库或单个代码库 monorepo 设置的子软件包中管理大量函数:

# firebase.json
"functions": {
  "codebase": "my-codebase"
  # NOTE: Codebase must be less than 63 characters and can contain only
  # lowercase letters, numeric characters, underscores, and dashes.
}

Firebase CLI v10.7.1 及更高版本支持 codebase 属性。

管理多个代码库

codebase 属性有助于简化对多个代码库的管理。我们来了解一下具有两个不同代码库的情况,这些代码库将函数部署到同一 Firebase 项目:

$  tree .
├── repoA
│   ├── firebase.json
│   └── functions
│       ├── index.js
│       └── package.json
└── repoB
    ├── firebase.json
    └── functions
        ├── index.js
        └── package.json

如果没有代码库注释,Firebase CLI 会在部署时提示您删除在其他代码库中定义的函数:

$ (cd repoA && firebase deploy --only functions)
...
i  functions: preparing functions directory for uploading...
  functions: functions folder uploaded successfully
The following functions are found in your project but do not exist in your local source code:
        fn1FromRepoB
        fn2FromRepoB
        ...
? Would you like to proceed with deletion? Selecting no will continue the rest of the deployments. (y/N)

您可以在每个项目代码库中 firebase.json 的函数配置部分中添加唯一的代码库注释,以避免此问题:

# repoA/firebase.json
"functions": {
  "codebase": "repo-a"
}

# repoB/firebase.json
"functions": {
  "codebase": "repo-b"
}

使用代码库注释时,Firebase CLI 不再提示您删除在即时代码库之外定义的函数:

$ (cd repoA && firebase deploy --only functions)
...
i  functions: preparing functions directory for uploading...
  functions: functions folder uploaded successfully
#  Gleefully ignores functions from repoB
i  functions: creating Node.js 16 function fnFromRepoA (us-central1)...
  Deploy Complete!

管理多个源软件包 (monorepo)

codebase 属性有助于简化对单个代码库中多个源软件包的管理。我们来分析一下这样的情况:您有一个 Firebase 项目目录,其中的函数定义分布在多个子软件包中:

$  tree .
├── firebase.json
├── teamA
│   ├── index.js
│   └── package.json
└── teamB
    ├── index.js
    └── package.json

此设置适用于以下用例:

  • 您有一个 monorepo 设置,并且让不同的团队在独立的软件包中管理自己的函数定义。
  • 您有一个函数具有大量外部依赖项和一个长时间运行的初始化,并且您希望将该函数与其他对延迟敏感的函数隔离开来。

如需支持此类 monrepo 设置,请在 firebase.json 中定义多个函数配置:

"functions": [
  {
    "source": "teamA",
    "codebase": "team-a"
  },
  {
    "source": "teamB",
    "codebase": "team-b"
  },
]

借助此配置,Firebase CLI 可以通过单个部署命令在所有软件包中部署函数:

$ firebase deploy --only functions
i  deploying functions
i  functions: preparing codebase team-a for deployment
i  functions: preparing codebase team-b for deployment
i  functions: creating Node.js 16 function team-a:helloATeam(us-central1)...
i  functions: creating Node.js 16 function team-b:helloBTeam(us-central1)...
...

您还可以部署特定的代码库:

$ firebase deploy --only functions:team-b
i  deploying functions
i  functions: preparing codebase team-b for deployment
i  functions: updating Node.js 16 function team-b:helloBTeam(us-central1)...
...

在多个文件中编写函数

刚开始使用 Cloud Functions 时,您可以将前几个函数放在同一个文件中:

index.js

const functions = require('firebase-functions/v1');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

main.py

from firebase_functions import https_fn

@https_fn.on_request()
def foo(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

@https_fn.on_request()
def bar(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello bar!")

这对于较多的函数而言可能难以管理。相反,您可以将每个函数的所有逻辑放在单独的文件中,并只将源文件用作导出列表:

Node.js

foo.js

const functions = require('firebase-functions/v1');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});

bar.js

const functions = require('firebase-functions/v1');
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

index.js

const foo = require('./foo');
const bar = require('./bar');
exports.foo = foo.foo;
exports.bar = bar.bar;

Python

foo.py

from firebase_functions import https_fn

@https_fn.on_request()
def foo(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

bar.py

from firebase_functions import https_fn

@https_fn.on_request()
def bar(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

main.py

from fn_impl.foo import *
from fn_impl.bar import *

此设置假定项目目录结构如下所示:

my-project
├── firebase.json
└── functions
    ├── fn_impl
    │   ├── __init__.py
    │   ├── foo.py
    │   └── bar.py
    ├── main.py
    └── requirements.txt

fn_impl:可以使用任意名称

__init__.py:必需,但可以为空

组函数

在许多项目中,可以将函数划分为多个逻辑组,每个逻辑组里的函数应一起部署和维护。例如,您可能有一组用于报告指标的函数:

metrics.js


const functions = require('firebase-functions/v1');
exports.usageStats = functions.https.onRequest((request, response) => {
  // ...
});
exports.nightlyReport = functions.https.onRequest((request, response) => {
  // ...
});

您可以在将这些函数导出到 index.js 文件中时将其放入一个组中:

index.js


// Export both functions from metrics.js in the "metrics" group:
//  - metrics-usageStats
//  - metrics-nightlyReport
exports.metrics = require('./metrics');

部署时,这些函数将以组名为前缀,因此在此示例中,函数将命名为 metrics-usageStatsmetrics-nightlyReport

部署函数时,您可以将操作限定在单个组:


firebase deploy --only functions:metrics

后续步骤

如需详细了解 Cloud Functions,请参阅: