Organiser plusieurs fonctions


Lorsque vous intégrez Cloud Functions à votre projet, votre code peut se développer pour contenir de nombreuses fonctions indépendantes. Vous pouvez avoir trop de fonctions pour les intégrer raisonnablement dans un seul fichier, ou différentes équipes peuvent déployer différents groupes de fonctions, ce qui crée le risque qu'une équipe écrase ou supprime accidentellement les fonctions d'une autre équipe. Cloud Functions propose différentes façons d'organiser votre code pour faciliter la navigation et la gestion de vos fonctions.

Organiser les fonctions dans des codebases

Vous pouvez utiliser la propriété codebase de l'objet de configuration des fonctions dans firebase.json pour gérer un grand ensemble de fonctions sur plusieurs dépôts ou sous-packages dans une configuration monorepo de dépôt unique:

# 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 propriété codebase est compatible avec la CLI Firebase version 10.7.1 et ultérieures.

Gérer plusieurs dépôts

La propriété codebase peut aider à simplifier la gestion de plusieurs dépôts. Examinons un cas dans lequel deux dépôts différents déploient des fonctions dans le même projet Firebase:

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

Sans annotations de codebase, la CLI Firebase vous aurait invité à supprimer les fonctions définies dans l'autre dépôt au moment du déploiement :

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

Pour éviter ce problème, ajoutez une annotation de codebase unique dans la section de configuration des fonctions de firebase.json dans chaque dépôt de projet :

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

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

Avec l'annotation du codebase, la CLI Firebase ne vous invite plus à supprimer les fonctions définies en dehors de votre dépôt immédiat :

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

Gérer plusieurs packages sources (monorepo)

La propriété codebase peut aider à simplifier la gestion de plusieurs packages sources dans un même dépôt. Imaginons que vous disposiez d'un répertoire de projet Firebase avec des définitions de fonction réparties sur plusieurs sous-packages :

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

Cette configuration convient aux cas d'utilisation suivants:

  • Vous avez configuré un monorépertoire et différentes équipes gèrent leurs propres définitions de fonction dans un package isolé.
  • Vous disposez d'une fonction avec une dépendance externe importante et une initialisation longue, et vous souhaitez l'isoler des autres fonctions sensibles à la latence.

Pour prendre en charge la configuration monrepo de cette manière, définissez plusieurs configurations de fonctions dans firebase.json :

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

Avec cette configuration, la CLI Firebase déploie les fonctions de tous les packages dans une seule commande de déploiement :

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

Vous pouvez également déployer un codebase spécifique :

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

Écrire des fonctions dans plusieurs fichiers

Lorsque vous commencez à utiliser Cloud Functions, vous pouvez placer vos premières fonctions dans un seul fichier :

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

Cela peut s'avérer difficile à gérer avec plusieurs fonctions. À la place, vous pouvez placer toute votre logique pour chaque fonction dans son propre fichier et utiliser votre fichier source comme liste d'exportations :

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 *

Cette configuration suppose une structure de répertoire de projet semblable à celle-ci :

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

fn_impl : peut porter n'importe quel nom

__init__.py : obligatoire, mais peut être vide

Fonctions de groupe

Dans de nombreux projets, les fonctions peuvent être séparées en groupes logiques qui doivent être déployés et gérés ensemble. Par exemple, vous pouvez avoir un groupe de fonctions utilisées pour générer des rapports sur les métriques:

metrics.js


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

Vous pouvez regrouper ces fonctions lorsque vous les exportez dans votre fichier index.js:

index.js


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

Lors du déploiement, le nom de leur groupe sera ajouté au début des fonctions. Dans cet exemple, les fonctions seront nommées metrics-usageStats et metrics-nightlyReport.

Lorsque vous déployez des fonctions, vous pouvez limiter l'action à un seul groupe :


firebase deploy --only functions:metrics

Étapes suivantes

Pour en savoir plus sur Cloud Functions, consultez les ressources suivantes :