Przygotowywanie rozszerzeń w Firebase do migracji do Cloud Functions

Z tego przewodnika dowiesz się, jak przeprowadzić migrację rozszerzeń z wycofanego środowiska Firebase Extensions do funkcji, którą użytkownicy mogą zainstalować i wdrożyć w swoim środowisku Cloud Functions dla Firebase (2 generacji) bazy kodu.

Jest to zalecana ścieżka migracji. Firebase będzie prowadzić listę rozszerzeń z oficjalnymi odpowiednikami w npm. Z tego przewodnika dowiesz się, jak utworzyć własne rozszerzenie.

W tym przewodniku jako przykładu używamy rozszerzenia Stream Firestore to BigQuery (firestore-bigquery-export). Każda sekcja kończy się przykładem, który pokazuje, jak wyglądało rozszerzenie przed migracją, a jak wygląda po niej w postaci pakietu @firebase/firestore-bigquery-export.

Zarejestruj się, aby uzyskać więcej informacji i pomoc w przenoszeniu rozszerzeń

Jeśli masz pytania dotyczące migracji z Firebase Extensions, możesz skontaktować się z nami pod adresem firebase-extensions-migrator-support-external@google.com. Będziemy też wysyłać e-maile do tej grupy, gdy będziemy aktualizować przewodnik o dodatkowe informacje na temat przygotowywania pakietów, testowania i dystrybuowania funkcji 2. generacji.

Aby dołączyć do tej grupy, wyślij wiadomość na adres firebase-extensions-migrator-support-external+subscribe@google.com. Otrzymasz e-maila z prośbą o potwierdzenie członkostwa. Musisz odpowiedzieć na tego e-maila, a nie klikać przycisku „Dołącz do tej grupy”.

Zanim zaczniesz

Aby przeprowadzić tę migrację, użyj tych funkcji Cloud Functions:

  • Konfiguracja sparametryzowana. Każdy parametr zadeklarowany w extension.yaml staje się zdefiniowanym parametrem w kodzie pakietu.

  • Deklaratywne role uprawnień i wymagane interfejsy API. Każda rola zadeklarowana w extension.yaml staje się wywołaniem requiresRole(...), a każdy interfejs API staje się wywołaniem requiresAPI(...) w kodzie funkcji. Podczas wdrażania interfejs Firebase CLI przypisuje zadeklarowane role do zarządzanego konta usługi środowiska wykonawczego i włącza zadeklarowane interfejsy API w Twoim imieniu.

  • Zdarzenia cyklu życia w przypadku Cloud Functions baz kodu. Cloud FunctionsBazy kodu obsługują teraz zdarzenia cyklu życia analogiczne do Firebase Extensions. Zadeklaruj konfigurację czasu instalacji i aktualizacji za pomocą elementów zaczepienia cyklu życia afterFirstDeploy(...)afterRedeploy(...). Zastępują one lifecycleEvents zadeklarowane w extension.yaml.

Sprawdź rozszerzenie

Zacznij od inwentaryzacji rozszerzenia, czyli pełnej listy wszystkich elementów, które rozszerzenie deklaruje, dostarcza i dokumentuje. Dzięki temu każda funkcja będzie miała zdefiniowane miejsce docelowe w funkcji 2 generacji i nic nie zostanie utracone podczas migracji.

Sprawdź te elementy i zwróć uwagę na to, co znajdziesz:

  • extension.yaml, który deklaruje parametry, funkcje, zdarzenia, role IAM, wymagane interfejsy API, tajne klucze i punkty zaczepienia cyklu życia.

  • functions/, który zawiera kod funkcji, zależności, konfigurację kompilacji, aktywatory i funkcje kolejki zadań.

  • README.md, PREINSTALL.mdPOSTINSTALL.md, które zawierają instrukcje konfiguracji, ostrzeżenia i informacje o płatnościach.

  • scripts/, który zawiera narzędzia do importowania, uzupełniania, zarządzania tożsamością i dostępem, naprawy lub migracji, a także inne narzędzia dostarczane wraz z rozszerzeniem.

Następnie dla każdego elementu w extension.yaml zdecyduj, gdzie ma się on znaleźć w pakiecie npm:

  • Przekształć konfigurację użytkownika w parametry Cloud Functions (sekcja 5).

  • Przekształć obiekty tajne w Cloud Functions obiekty tajne (sekcja 6).

  • Przekształć role uprawnień w deklaracje requiresRole(...) (sekcja 8).

  • Przekształć wymagane interfejsy API Google w deklaracje requiresAPI(...), jeśli jest to odpowiednie (sekcja 8).

  • Przekształć wywołania instalacji i aktualizacji w deklaracje afterFirstDeploy(...)afterRedeploy(...) (sekcja 8).

Przykład: przesyłanie strumieniowe danych z Firestore do BigQuery

Odczytanie plików firestore-bigquery-export/extension.yaml i functions/ daje ten spis:

W pliku extension.yaml Liczba / wartość Gdzie trafiają dane
parametry 25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) Cloud Functions parametry (sekcja 5)
interfejsy API bigquery.googleapis.com requiresAPI(...) (sekcja 7)
role bigquery.dataEditor, datastore.user, bigquery.user requiresRole(...) (sekcja 7)
zasoby 1 aktywator zdarzeń (fsexportbigquery) + funkcje kolejki zadań (initBigQuerySync, setupBigQuerySync) Funkcje wyeksportowanego pakietu (sekcja 3)
lifecycleEvents onInstall → initBigQuerySync; onUpdate / onConfigure → setupBigQuerySync afterFirstDeploy / afterRedeploy (sekcja 9)
scripts/ import/ (backfill), gen-schema-view/ zachowane jako skrypty (nie są tu brane pod uwagę),

Rozszerzenie nie deklaruje żadnego typu: secret params, więc w sekcji 6 tego przewodnika nie ma niczego do migracji. Wywoływacz zdarzeń jest już 2 generacji, a tylko funkcje kolejki zadań są nadal 1 generacji (ma to znaczenie w sekcji 3).

Aktualizowanie pliku package.json

Zaktualizuj plik package.json rozszerzenia. Jeśli przenosisz jedno rozszerzenie, może to być katalog główny package.json. Jeśli przenosisz wiele rozszerzeń w jednym repozytorium, każde z nich powinno mieć własny pakiet.

Minimalne wersje pakietu SDK. Zadeklaruj firebase-functions >= 7.3 i firebase-admin >= 14.2.0 jako zależności. Zadeklaruj swoją wersję firebase-functions jako zależność równorzędną

{
  "name": "<package-name>",
  "version": "1.0.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".": {
      "types": "./lib/index.d.ts",
      "default": "./lib/index.js"
    }
  },
  "engines": {
    "node": ">=22"
  },
  "peerDependencies": {
    "firebase-functions": "^7.3.0"
  },
  "dependencies": {
    "firebase-functions": "^7.3.0",
    "firebase-admin": "^14.2.0"
  }
}

Zadeklaruj firebase-functions jako zależność równorzędną oprócz normalnej zależności, aby projekt Cloud Functions użytkowników miał tę samą wersję pakietu SDK, w której napisano Twoją bibliotekę.

Przykład: przesyłanie strumieniowe danych z Firestore do BigQuery

Przed. Plik functions/package.json rozszerzenia jest prywatny, zawiera identyfikator rozszerzenia i deklaruje firebase-functions jako bezpośrednią zależność:

{
  "name": "firestore-bigquery-export",
  "main": "lib/index.js",
  "private": true,
  "dependencies": {
    "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
    "firebase-admin": "^14.2.0",
    "firebase-functions": "^6.3.2"
  }
}

Po Pakiet do opublikowania: nazwa z zakresem, mapa eksportów i firebase-functions przeniesione do peerDependencies:

{
  "name": "@firebase/firestore-bigquery-export",
  "version": "0.1.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".":     { "types": "./lib/index.d.ts", "default": "./lib/index.js" },  },
  "engines": { "node": ">=22" },
  "peerDependencies": { "firebase-functions": "^7.3.0" },
  "dependencies": {
      "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
      "firebase-admin": "^14.2.0",
      "firebase-functions": "^7.3.0"
    }
}

Uaktualnianie funkcji z 1 generacji do 2 generacji

Jeśli rozszerzenie nadal eksportuje funkcje 1 generacji, przekonwertuj każdą funkcję na jej odpowiednik 2 generacji. Zaimportuj moduły z firebase-functions/... i przekaż ustawienia środowiska wykonawczego w opcjach funkcji.

Możesz zminimalizować wysiłek związany z przepisywaniem kodu dzięki rozbijaniu struktury zdarzeń w przypadku poprawek w pakiecie SDK 2 generacji i uniknąć przepisywania logiki funkcji, ponieważ pakiet SDK 2 generacji udostępnia teraz parametry V1 jako pola w obiekcie zdarzenia, co pozwala używać rozbitych/nazwanych parametrów i nie zmieniać logiki biznesowej.

Przed. 1 generacja:

import * as functions from "firebase-functions/v1";

export const sync = functions.firestore
  .document("{collectionId}/{documentId}")
  .onWrite(async (change, context) => {
    await handleWrite(change.before, change.after, context.params);
  });

Po 2 generacja:

import { onDocumentWritten } from "firebase-functions/firestore";

export const syncV2 = onDocumentWritten(
  { document: "{collectionId}/{documentId}" },
  async ({change,context}) =>
    await handleWrite(change.before, change.after, context.params);
);

Pełną listę różnic między funkcjami 1 generacji i 2 generacji znajdziesz w Cloud Functionsporównaniu wersji.

Konwertowanie parametrów i obiektów tajnych rozszerzenia

Parametry konwersji

Każdy parametr zadeklarowany w extension.yaml staje się parametrem Cloud Functions.

Konwertuj odczyty bezpośrednie środowiska:

const collectionPath = process.env.COLLECTION_PATH;

w parametrach Cloud Functions:

import { defineString } from "firebase-functions/params";
import { onDocumentWritten} from "firebase-functions/firestore";

const collectionPath = defineString("COLLECTION_PATH");

// Pass the param directly when used as a placeholder (e.g. trigger path)
export const sync = onDocumentWritten(
  { document: collectionPath },
  async (event) => {
    // Call .value() to read the string inside a handler
    const path = collectionPath.value();
    await handleWrite(path, event);
  }
);

Użyj collectionPath.value(), aby odczytać ciąg w obsłudze, i collectionPath bezpośrednio w miejscu, w którym oczekiwany jest symbol zastępczy, np. w ścieżce wyzwalacza funkcji.

Interfejs Firebase CLI wykrywa parametry i odczytuje ich wartości z plików .env lub .env.projectId albo wyświetla użytkownikom prośby o podanie tych wartości podczas wdrażania. Zachowaj te same nazwy parametrów, aby wartości z istniejącej instalacji zostały przeniesione.

Ważne jest, aby nie zmieniać nazw parametrów zadeklarowanych w kodzie. Migracja rozszerzenia automatycznie zachowa dotychczasową wartość parametru użytkownika, ale tylko wtedy, gdy nazwy pozostaną bez zmian.

Przykład: przesyłanie strumieniowe Firestore do BigQuery Przed Parametr zadeklarowany w extension.yaml, odczytany jako zmienna środowiskowa w config.ts:

# extension.yaml
-   param: COLLECTION_PATH
  label: Collection path
  type: string
  required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,

Po Jeden defineString; interfejs wiersza poleceń go wykrywa i odczytuje z .env:

// src/config.ts
import { defineString } from "firebase-functions/params";

collectionPath: defineString("COLLECTION_PATH", {
  label: "Collection path",
  // We now support "nonEmpty: true" to ensure a value other than the empty string
  // is entered, analagous to "required: true" in extensions.yaml
  input: { text: { nonEmpty: true} }
}),

Nazwa parametru nie uległa zmianie, więc istniejący plik .env nadal działa.

Konwertowanie obiektów tajnych

W pliku extension.yaml deklarujesz obiekty tajne za pomocą typu: secret. Środowisko wykonawcze rozszerzeń przechowuje je i wiąże, dzięki czemu kod rozszerzenia może bezpośrednio odczytywać process.env.PARAM_NAME. W typowej bazie kodu Cloud Functions deklarujesz i wiążesz każdy klucz tajny w sposób jawny:

import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";

const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);

Po przeniesieniu rozszerzenia do pakietu lub zestawu npm odwołania do kluczy tajnych będą zarządzane w pliku .env użytkownika. Ważne jest, aby nie zmieniać nazw kluczy tajnych zadeklarowanych w kodzie w ogóle. Podczas migracji zostaną przeniesione odpowiednie dane logowania użytkowników.

Przykład: wysyłanie e-maila z Cloud Firestore

Przed. Zmienne środowiskowe MAIL_COLLECTION i SMTP_PASSWORD są odczytywane jako surowe zmienne środowiskowe w pliku config.ts:

# extension.yaml
-   param: MAIL_COLLECTION
  label: Email documents collection
  type: string
  default: mail
  required: true

-   param: SMTP_PASSWORD
  label: SMTP password
  type: secret
// functions/src/config.ts
mailCollection: process.env.MAIL_COLLECTION,
smtpPassword: process.env.SMTP_PASSWORD,

Po Jeden plik defineString i jeden plik defineSecret; interfejs wiersza poleceń wykrywa oba pliki i odczytuje dane z pliku .env

import { defineString, defineSecret } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";

const mailCollection = defineString("MAIL_COLLECTION",{ label: "Email documents collection",
 default: "mail"
});

const smtpPassword = defineSecret("SMTP_PASSWORD", { label: "SMTP password" });

export const processQueue = onDocumentWritten(
  { document: `${mailCollection}/{documentId}`, secrets: [smtpPassword] },
  async (event) => {
    const collection = mailCollection.value();
    const password = smtpPassword.value();
    // ...
  }
);

Migracja wewnętrznych wywołań kolejki zadań

Niektóre rozszerzenia umieszczają zadania w własnych kolejkach zadań z poziomu kodu funkcji, używając Firebase Admin SDK. Różni się to od otrzymywania wysłanego zadania (omówionego w sekcjach Uaktualnianie funkcjiKonwertowanie wywołań zwrotnych cyklu życia). W tym przypadku kod jest producentem, który wywołuje queue.enqueue(...).

W poprzednich wersjach Admin SDK rozszerzenia musiały przekazywać własny identyfikator instancji rozszerzenia jako drugi parametr, aby kierować funkcję kolejki zadań w tym samym rozszerzeniu. Od wersji 14.2.0 pakietu `firebase-admin` nie jest to wymagane ani zalecane. Interfejs Task Queue API będzie teraz domyślnie kierować zadania do kolejek zadań w tym samym kontekście (np. rozszerzeniu). Możesz bezpiecznie usunąć ten parametr z kodu zarówno w rozszerzeniu, jak i w funkcjach autonomicznych. Usunięcie tego parametru zapewnia przenośność i zgodność z przyszłymi wersjami.

Wszystkie inne elementy wywołania enqueue, czyli ścieżka zasobu locations/region/functions/name, ładunek zadania i logika ponawiania, pozostają bez zmian.

Więcej informacji o kolejkowaniu funkcji za pomocą Cloud Tasks znajdziesz na stronie /docs/functions/task-functions.

Przed. Rozszerzenie 1 generacji

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${config.location}/functions/syncBigQuery`,
  process.env.EXT_INSTANCE_ID, // extension instance ID, injected by the runtime
);
await queue.enqueue(taskData);

Po Rozszerzenie 2 generacji

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${process.env.FUNCTION_REGION}/functions/syncBigQuery`);
await queue.enqueue(taskData);

Jeśli wywołanie kolejki dotyczy bazy kodu z prefiksem, wykryta nazwa funkcji również będzie miała prefiks (np. orders-syncBigQuery).

Deklarowanie wymaganych interfejsów API i ról uprawnień

Przenieś wymagania rozszerzenia dotyczące IAM i interfejsu API z pliku extension.yaml do:

import { requiresAPI, requiresRole } from "firebase-functions"

requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");

W przypadku deklaratywnego zabezpieczenia interfejs Firebase CLI tworzy lub aktualizuje zarządzane konto usługi środowiska wykonawczego dla bazy kodu i przyznaje mu sumę wszystkich zadeklarowanych ról. Poinformuj użytkowników, że wszystkie funkcje w bazie kodu działają z tymi rolami, chyba że końcowy interfejs API obsługuje węższy model.

Przykład: przesyłanie strumieniowe danych z Firestore do BigQuery

Przed. Zadeklarowane w pliku extension.yaml; środowisko wykonawcze rozszerzeń włączyło interfejs API i przyznało role zarządzanemu kontu:

apis:
  -   apiName: bigquery.googleapis.com
roles:
  -   role: bigquery.dataEditor
  -   role: datastore.user
  -   role: bigquery.user

Po Zadeklarowane w kodzie za pomocą funkcji requiresAPI i requiresRole:

import { requiresAPI, requiresRole } from "firebase-functions/";
requiresAPI("bigquery.googleapis.com",
  "Needed to write changelog rows and views");
requiresRole("roles/biguqery.dataEditor");
requiresRole("roles/datastore.user");
requiresRole("roles/bigquery.user");

Konwertowanie ciekawostek dotyczących cyklu życia

Jeśli rozszerzenie wywołuje na przykład getExtensions().runtime()setProcessingState lub setFatalError, usuń te wywołania, ponieważ w przypadku wywołania z normalnie wdrożonej funkcji 2 generacji spowodują one błąd. Stan cyklu życia jest teraz określany przez afterFirstDeployafterRedeploy, w przypadku których śledzenie stanu nie jest używane.

Firebase Extensions może uruchamiać konfigurację, gdy użytkownik zainstaluje, zaktualizuje lub ponownie skonfiguruje rozszerzenie. W pakiecie npm zadeklaruj w kodzie równoważne działania związane z cyklem życia.

Aby skonfigurować urządzenie po raz pierwszy:

import { afterFirstDeploy } from "firebase-functions/lifecycle";
import { onTaskDispatched } from "firebase-functions/tasks";

export const runInitialSetup = onTaskDispatched(async (request) => {
  await initializeResources(request.data);
});

afterFirstDeploy({
  task: {
    function: "runInitialSetup",
    body: {}
  }
});

W przypadku aktualizacji konfiguracji lub kodu:

import { afterRedeploy } from "firebase-functions/lifecycle";

afterRedeploy({
  task: {
    function: "runInitialSetup",
    body: { reconcile: true }
  }
});

Zadbaj o to, aby działania związane z cyklem życia były idempotentne. Jeśli wysyłanie lub wykonywanie się nie powiedzie, użytkownicy mogą ręcznie ponownie uruchomić te skrypty:

firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME

Przykład: przesyłanie strumieniowe danych z Firestore do BigQuery

Przed. lifecycleEvents w extension.yaml, czynnik kosztowy: środowisko wykonawcze rozszerzeń:

lifecycleEvents:
  onInstall:
    function: initBigQuerySync
    processingMessage: Configuring BigQuery Sync.
  onUpdate:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync
  onConfigure:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync

Po Zadeklarowane w kodzie; zadanie zapewnia BigQuery przy pierwszym wdrożeniu:

import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";

afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });

Aprowizacja jest idempotentna, więc ponowne uruchomienie powoduje uzgodnienie zbioru danych, tabeli i widoków. Użytkownicy mogą ponownie uruchomić funkcję ręcznie za pomocą polecenia firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME.

Konfigurowanie dokumentów dla użytkowników

  • Napisz README, w którym wyjaśnisz co najmniej:

  • Wartości .env wymagane przez pakiet.

  • obiekty tajne wymagane przez pakiet oraz sposób przenoszenia istniejących wartości obiektów tajnych.

  • Role uprawnień zadeklarowane w pakiecie za pomocą requiresRole(...).

  • Interfejsy API Google, które pakiet włącza lub których wymaga.

  • Punkty zaczepienia cyklu życia zadeklarowane przez pakiet i sposób ich ponownego ręcznego uruchomienia.

  • Uwagi dotyczące płatności.

  • Co się zmieniło w porównaniu z oryginalnym rozszerzeniem.

Przykład: przesyłanie strumieniowe danych z Firestore do BigQuery

Plik README pakietu zawiera konkretną tabelę „Co się zmieniło”:

Potencjalny problem Jako rozszerzenie As @firebase/firestore-bigquery-export
Konfiguracja Parametry rozszerzenia Parametry funkcji za pomocą pliku .env
Uprawnienia Przyznane przez rozszerzenia requiresRole(...), zastosowane podczas wdrażania
Udostępniam Zadanie cyklu życia według rozszerzeń Zadanie afterFirstDeploy / afterRedeploy
Nazwy funkcji ext-instanceId-fsexportbigquery fsexportbigquery (opcjonalnie z prefiksem)

Testowanie funkcji 2 generacji

Powinna być teraz dostępna funkcja 2 generacji, która po wdrożeniu będzie działać identycznie jak nowa instalacja rozszerzenia. Ostatnim krokiem jest sprawdzenie i rozwiązanie wszelkich problemów, które mogły się pojawić po drodze.

Upewnij się, że używasz firebase-tools >= w wersji 15.25.1 i wdrażasz przekonwertowaną funkcję 2 generacji w projekcie testowym z odpowiednimi zasobami, aby przetestować jej działanie. Jeśli masz już projekt testowy skonfigurowany na potrzeby testowania rozszerzenia, użyj polecenia:

firebase deploy --only functions

Po wpisaniu tego polecenia wypełnij kreator, podając wartości parametrów w taki sam sposób, jak w przypadku formularza instalacji w konsoli Firebase dla rozszerzenia.

Przykład: przesyłanie strumieniowe danych z Firestore do BigQuery

Sprawdzamy synchronizację Cloud FirestoreBigQuery na całej długości:

  1. W konsoli Cloud Firestore utwórz kolekcję, którą ustawisz jako COLLECTION_PATH (użytkownicy), jeśli jeszcze nie istnieje.
  2. Utwórz dokument o nazwie bigquery-mirror-test zawierający dowolne pola z dowolnymi wartościami.
  3. W konsoli BigQuery utwórz zapytanie do tabeli z surowymi danymi dziennika zmian. Powinien zawierać jeden wiersz rejestrujący utworzenie dokumentu:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
  1. Wyślij zapytanie o najnowszą wersję, która powinna zwrócić najnowsze zdarzenie zmiany dla jedynego dokumentu: bigquery-mirror-test
SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
  1. Usuń dokument bigquery-mirror-test w Cloud Firestore. Znika z widoku najnowszych zmian, a do tabeli surowego dziennika zmian dodawane jest zdarzenie DELETE.

Pełną historię pojedynczego dokumentu możesz sprawdzić za pomocą tych narzędzi:

SELECT *
   FROM `PROJECT_ID.analytics.users_raw_changelog`
   WHERE document_name = "bigquery-mirror-test"
   ORDER BY timestamp ASC

Różnice w porównaniu z testowaniem rozszerzenia:

  • Reguła jest wdrażana jako fsexportbigquery (opcjonalnie z prefiksem kodu), a nie ext-&lt;instanceId&gt;-fsexportbigquery. Poszukaj tej nazwy w panelu Cloud Functions i dziennikach.
  • Kod będzie teraz działać w Firebase Local Emulator Suite jak zwykłe funkcje. Wartości parametrów, które mają być używane w emulatorze, możesz ustawić za pomocą polecenia .env.local. Możesz też testować jednostkowo kod za pomocą pakietu SDK firebase-functions-test zgodnie z opisem w sekcji Testowanie jednostkoweCloud Functions.
  • Inicjowanie nie jest już oparte na środowisku wykonawczym rozszerzeń. Jeśli po wdrożeniu brakuje tabeli dziennika zmian, ponownie uruchom ręcznie zadanie konfiguracji: firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. Zadanie jest idempotentne, więc ponowne jego uruchomienie spowoduje uzgodnienie zbioru danych, tabeli i widoków.
  • Wartości parametrów pochodzą z .env, a nie z formularza instalacji, więc ponowne uruchomienia firebase deploy są nieinteraktywne po zakończeniu .env.