Organizar múltiples funciones


A medida que integres Cloud Functions en tu proyecto, tu código podría expandirse para contener muchas funciones independientes. Es posible que tenga demasiadas funciones para caber razonablemente en un solo archivo, o diferentes equipos pueden implementar diferentes grupos de funciones, creando el riesgo de que un equipo sobrescriba o borre accidentalmente las funciones de otro equipo. Cloud Functions ofrece diferentes formas de organizar su código para facilitar la navegación y el mantenimiento de sus funciones.

Organizar funciones en bases de código.

Puedes usar la propiedad codebase del objeto de configuración de funciones en firebase.json para administrar una gran colección de funciones en múltiples repositorios o subpaquetes dentro de una configuración monorepo de un único repositorio:

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

La propiedad codebase es compatible con Firebase CLI v10.7.1 y versiones posteriores.

Administrar múltiples repositorios

La propiedad codebase puede ayudar a simplificar la gestión de múltiples repositorios. Examinemos un caso en el que tiene dos repositorios diferentes que implementan funciones en el mismo proyecto de Firebase:

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

Sin las anotaciones de la base de código, Firebase CLI le habría solicitado que eliminara las funciones definidas en el otro repositorio en el momento de la implementación:

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

Puedes evitar este problema agregando una anotación de base de código única en la sección de configuración de funciones de firebase.json en cada repositorio de proyecto:

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

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

Con la anotación de la base de código, Firebase CLI ya no le solicita que elimine funciones definidas fuera de su repositorio inmediato:

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

Administrar múltiples paquetes fuente (monorepo)

La propiedad codebase puede ayudar a simplificar la administración de múltiples paquetes fuente en un único repositorio. Examinemos un caso en el que tiene un directorio de proyecto de Firebase con definiciones de funciones distribuidas en varios subpaquetes:

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

Esta configuración se adapta a los siguientes casos de uso:

  • Tiene una configuración monorepo y diferentes equipos administran sus propias definiciones de funciones en un paquete aislado.
  • Tiene una función con una gran dependencia externa y una inicialización de larga duración, y desea aislar esa función de otras funciones sensibles a la latencia.

Para admitir una configuración de monrepo como esta, defina configuraciones de funciones múltiples en firebase.json :

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

Con esta configuración, Firebase CLI implementa funciones de todos los paquetes en un solo comando de implementación:

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

También puedes implementar una 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)...
...

Escribir funciones en múltiples archivos.

Al comenzar con Cloud Functions, puede colocar sus primeras funciones en un solo archivo:

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

Esto puede resultar difícil de gestionar con más de unas pocas funciones. En su lugar, puedes poner toda tu lógica para cada función en su propio archivo y usar tu archivo fuente como una lista de exportaciones:

Nodo.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ón

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 configuración asume una estructura de directorio de proyecto como la siguiente:

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

fn_impl : puede tener cualquier nombre

__init__.py : obligatorio, pero puede estar vacío

Funciones de grupo

En muchos proyectos, las funciones se pueden separar en grupos lógicos que deben implementarse y mantenerse juntos. Por ejemplo, es posible que tenga un grupo de funciones utilizadas para informar métricas:

metrics.js


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

Puede poner estas funciones en un grupo al exportarlas en su archivo index.js :

index.js


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

Cuando se implementen, las funciones tendrán el prefijo del nombre de su grupo, por lo que en este ejemplo las funciones se denominarían metrics-usageStats y metrics-nightlyReport .

Al implementar funciones, puede limitar la acción a un solo grupo:


firebase deploy --only functions:metrics

Próximos pasos

Para obtener más información sobre Cloud Functions, consulte: