Organize múltiplas funções


À medida que você integra o Cloud Functions ao seu projeto, seu código pode se expandir para conter muitas funções independentes. Você pode ter muitas funções para caber razoavelmente em um único arquivo, ou diferentes equipes podem implantar diferentes grupos de funções, criando o risco de uma equipe substituir ou excluir acidentalmente as funções de outra equipe. O Cloud Functions oferece diferentes maneiras de organizar seu código para facilitar a navegação e a manutenção de suas funções.

Organize funções em bases de código

Você pode usar a propriedade codebase do objeto de configuração de funções em firebase.json para gerenciar uma grande coleção de funções em vários repositórios ou subpacotes dentro de uma configuração monorepo de repositório único:

# 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.
}

A propriedade codebase é compatível com Firebase CLI v10.7.1 e superior.

Gerenciando vários repositórios

A propriedade codebase pode ajudar a simplificar o gerenciamento de vários repositórios. Vamos examinar um caso em que você tem dois repositórios diferentes que implantam funções no mesmo projeto do Firebase:

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

Sem anotações de base de código, a CLI do Firebase solicitaria que você excluísse funções definidas no outro repositório no momento da implantação:

$ (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)

Você pode evitar esse problema adicionando uma anotação de base de código exclusiva na seção de configuração de funções do firebase.json em cada repositório do projeto:

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

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

Com a anotação de base de código, a CLI do Firebase não solicita mais que você exclua funções definidas fora do seu repositório imediato:

$ (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!

Gerenciando vários pacotes de origem (monorepo)

A propriedade codebase pode ajudar a simplificar o gerenciamento de vários pacotes de origem em um único repositório. Vamos examinar um caso em que você tem um diretório de projeto do Firebase com definições de funções espalhadas por vários subpacotes:

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

Essa configuração se adapta aos seguintes casos de uso:

  • Você tem uma configuração monorepo e diferentes equipes gerenciam suas próprias definições de função em um pacote isolado.
  • Você tem uma função com forte dependência externa e inicialização demorada e deseja isolar essa função de outras funções sensíveis à latência.

Para oferecer suporte à configuração do monrepo como esta, defina configurações de múltiplas funções em firebase.json :

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

Com esta configuração, a CLI do Firebase implanta funções de todos os pacotes em um único comando de implantação:

$ 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)...
...

Você também pode implantar uma base de código específica:

$ 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)...
...

Escreva funções em vários arquivos

Ao começar a usar o Cloud Functions, você pode colocar suas primeiras funções em um único arquivo:

index.js

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

principal.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!")

Isso pode ser difícil de gerenciar com mais do que algumas funções. Em vez disso, você pode colocar toda a lógica de cada função em seu próprio arquivo e usar o arquivo de origem como uma lista de exportações:

Node.js

foo.js

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

bar.js

const functions = require('firebase-functions');
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;

Pitão

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!")

principal.py

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

Esta configuração assume uma estrutura de diretórios de projeto como a seguinte:

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

fn_impl : Pode ter qualquer nome

__init__.py : obrigatório, mas pode estar vazio

Funções de grupo

Em muitos projetos, as funções podem ser separadas em grupos lógicos que devem ser implantados e mantidos em conjunto. Por exemplo, você pode ter um grupo de funções usadas para gerar relatórios de métricas:

métricas.js


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

Você pode colocar essas funções em um grupo ao exportá-las em seu arquivo index.js :

index.js


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

Quando implantadas, as funções serão prefixadas com o nome do seu grupo, portanto, neste exemplo, as funções seriam denominadas metrics-usageStats e metrics-nightlyReport .

Ao implantar funções você pode limitar a ação a um único grupo:


firebase deploy --only functions:metrics

Próximos passos

Para saber mais sobre o Cloud Functions, consulte: