Uporządkuj wiele funkcji


Gdy integrujesz Cloud Functions ze swoim projektem, Twój kod może się rozwijać i zawierać wiele niezależnych funkcji. Możesz mieć zbyt wiele funkcji, aby zmieścić się w jednym pliku, lub różne zespoły mogą wdrożyć różne grupy funkcji, co stwarza ryzyko zastąpienia lub przypadkowego usunięcia funkcji innego zespołu. Cloud Functions oferuje różne sposoby porządkowania kodu, aby ułatwić poruszanie się po funkcjach i ich obsługę.

Uporządkuj funkcje w bazach kodu

Możesz użyć właściwości codebase obiektu konfiguracji funkcji w firebase.json, aby zarządzać dużym zbiorem funkcji w wielu repozytoriach lub podpakietach w ramach pojedynczej konfiguracji monorepozytorium:

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

Właściwość codebase jest obsługiwana w interfejsie wiersza poleceń Firebase w wersji 10.7.1 i nowszych.

Zarządzanie wieloma repozytoriami

Właściwość codebase może uprościć zarządzanie wieloma repozytoriami. Przeanalizujmy przypadek, w którym masz 2 różne repozytoria, które wdrażają funkcje w tym samym projekcie Firebase:

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

Bez adnotacji bazy kodu interfejs wiersza poleceń Firebase poprosiłby o usunięcie funkcji zdefiniowanych w innym repozytorium w momencie wdrażania:

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

Możesz uniknąć tego problemu, dodając unikalną adnotację bazy kodu w sekcji konfiguracji funkcji pliku firebase.json w każdym repozytorium projektów:

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

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

Dzięki adnotacjom bazy kodu interfejs wiersza poleceń Firebase nie wyświetla już próśb o usunięcie funkcji zdefiniowanych poza Twoim bezpośrednim repozytorium:

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

Zarządzanie wieloma pakietami źródłowymi (monorepo)

Właściwość codebase może uprościć zarządzanie wieloma pakietami źródłowymi w jednym repozytorium. Przyjrzyjmy się przykładowi, w którym masz katalog projektu Firebase z definicjami funkcji rozmieszczonymi w kilku pakietach podrzędnych:

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

Ta konfiguracja pasuje do tych przypadków użycia:

  • Masz konfigurację monorepo i różne zespoły zarządzają własnymi definicjami funkcji w osobnym pakiecie.
  • Masz funkcję z dużą zależność zewnętrzną i długo trwającą inicjacją, ale chcesz odizolować tę funkcję od innych funkcji wrażliwych na czas oczekiwania.

Aby obsługiwać konfigurację Monrepo w ten sposób, zdefiniuj konfiguracje wielu funkcji w firebase.json:

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

Dzięki takiej konfiguracji interfejs wiersza poleceń Firebase wdraża funkcje ze wszystkich pakietów w jednym poleceniu wdrażania:

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

Możesz też wdrożyć określoną bazę kodu:

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

Zapisywanie funkcji w wielu plikach

Gdy rozpoczynasz korzystanie z Cloud Functions, możesz umieścić kilka pierwszych funkcji w jednym pliku:

Plik index.js

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

Zarządzanie tym ustawieniem może być trudne przy wykorzystaniu więcej niż kilku funkcji. Zamiast tego możesz umieścić wszystkie logiki dla każdej funkcji w osobnym pliku i użyć pliku źródłowego jako listy eksportów:

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;

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 *

Ta konfiguracja zakłada strukturę katalogów projektu podobną do tej:

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

fn_impl: może mieć dowolną nazwę.

__init__.py: wymagany, ale może być pusty

Funkcje grupy

W wielu projektach funkcje można podzielić na grupy logiczne, które należy wdrażać i utrzymywać razem. Możesz np. mieć grupę funkcji służących do raportowania danych:

metrics.js


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

Podczas eksportowania do pliku index.js możesz umieścić te funkcje w grupie:

index.js


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

Wdrożone funkcje będą poprzedzone nazwą grupy, więc w tym przykładzie będą nosić nazwy metrics-usageStats i metrics-nightlyReport.

Podczas wdrażania funkcji możesz ograniczyć działanie do jednej grupy:


firebase deploy --only functions:metrics

Dalsze kroki

Więcej informacji o Cloud Functions znajdziesz tutaj: