Man mano che integri Cloud Functions nel tuo progetto, il codice potrebbe espandersi fino a contenere molte funzioni indipendenti. Potresti avere troppe funzioni per adattarsi ragionevolmente a un singolo file oppure team diversi potrebbero eseguire il deployment di gruppi di funzioni diversi, creando il rischio che un team sovrascriva o elimini accidentalmente le funzioni di un altro team. Cloud Functions offre diversi modi per organizzare il codice in modo da semplificare la navigazione e la manutenzione delle funzioni.
Organizzare le funzioni nei codebase
Puoi utilizzare la proprietà codebase dell'oggetto di configurazione delle funzioni in firebase.json per gestire una raccolta di grandi dimensioni di funzioni in più repository o pacchetti secondari all'interno di una configurazione monorepo di un singolo repository:
# 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 proprietà codebase è supportata nell'interfaccia a riga di comando di Firebase v10.7.1 e versioni successive.
Gestire più repository
La proprietà codebase può semplificare la gestione di più repository. Esaminiamo un caso in cui hai due repository diversi che eseguono il deployment delle funzioni nello stesso progetto Firebase:
$ tree .
├── repoA
│ ├── firebase.json
│ └── functions
│ ├── index.js
│ └── package.json
└── repoB
├── firebase.json
└── functions
├── index.js
└── package.json
Senza le annotazioni del codebase, l'interfaccia a riga di comando di Firebase ti avrebbe chiesto di eliminare le funzioni definite nell'altro repository al momento del deployment:
$ (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)
Puoi evitare questo problema aggiungendo un'annotazione del codebase univoca nella sezione di configurazione delle funzioni di firebase.json in ogni repository del progetto:
# repoA/firebase.json
"functions": {
"codebase": "repo-a"
}
# repoB/firebase.json
"functions": {
"codebase": "repo-b"
}
Con l'annotazione del codebase, l'interfaccia a riga di comando di Firebase non ti chiede più di eliminare le funzioni definite al di fuori del repository immediato:
$ (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!
Gestire più pacchetti di origine (monorepo)
La proprietà codebase può semplificare la gestione di più pacchetti di origine in un singolo repository. Esaminiamo un caso in cui hai una directory del progetto Firebase con definizioni di funzioni distribuite su più pacchetti secondari:
$ tree .
├── firebase.json
├── teamA
│ ├── index.js
│ └── package.json
└── teamB
├── index.js
└── package.json
Questa configurazione è adatta ai seguenti casi d'uso:
- Hai una configurazione monorepo e team diversi gestiscono le proprie definizioni di funzioni in un pacchetto isolato.
- Hai una funzione con una dipendenza esterna pesante e un'inizializzazione a lunga esecuzione e vuoi isolare questa funzione da altre funzioni sensibili alla latenza.
Per supportare una configurazione monorepo come questa, definisci più configurazioni di funzioni in firebase.json:
"functions": [
{
"source": "teamA",
"codebase": "team-a"
},
{
"source": "teamB",
"codebase": "team-b"
},
]
Con questa configurazione, l'interfaccia a riga di comando di Firebase esegue il deployment delle funzioni da tutti i pacchetti in un unico comando di deployment:
$ 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)...
...
Puoi anche eseguire il deployment di un codebase specifico:
$ 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)...
...
Scrivere funzioni in più file
Quando inizi a utilizzare Cloud Functions, potresti inserire le prime funzioni in un singolo file:
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!")
Questo può diventare difficile da gestire con più di poche funzioni. Puoi invece inserire tutta la logica di ogni funzione nel proprio file e utilizzare il file di origine come elenco di esportazioni:
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 *
Questa configurazione presuppone una struttura di directory del progetto simile alla seguente:
my-project
├── firebase.json
└── functions
├── fn_impl
│ ├── __init__.py
│ ├── foo.py
│ └── bar.py
├── main.py
└── requirements.txt
fn_impl: può avere qualsiasi nome
__init__.py: obbligatorio, ma può essere vuoto
Raggruppare le funzioni
In molti progetti, le funzioni possono essere suddivise in gruppi logici che devono essere sottoposti a deployment e gestiti insieme. Ad esempio, potresti avere un gruppo di funzioni utilizzate per la generazione di report sulle metriche:
metrics.js
const functions = require('firebase-functions/v1'); exports.usageStats = functions.https.onRequest((request, response) => { // ... }); exports.nightlyReport = functions.https.onRequest((request, response) => { // ... });
Puoi inserire queste funzioni in un gruppo quando le esporti nel file index.js:
index.js
// Export both functions from metrics.js in the "metrics" group: // - metrics-usageStats // - metrics-nightlyReport exports.metrics = require('./metrics');
Quando viene eseguito il deployment, le funzioni avranno come prefisso il nome del gruppo, quindi in questo esempio le funzioni verranno denominate metrics-usageStats e metrics-nightlyReport.
Quando esegui il deployment delle funzioni, puoi limitare l'azione a un singolo gruppo:
firebase deploy --only functions:metrics
Passaggi successivi
Per saperne di più su Cloud Functions, consulta: