In dieser Anleitung erfahren Sie, wie Sie Ihre Erweiterungen von der eingestellten Firebase Extensions-Umgebung zu einer Funktion migrieren, die Ihre Nutzer in ihrem eigenen Cloud Functions für die Firebase-Codebasis (2. Generation) installieren und bereitstellen.
Dies ist der empfohlene Migrationspfad. Firebase führt eine Liste von Erweiterungen mit offiziellen npm-Entsprechungen. In diesem Leitfaden wird beschrieben, wie Sie Ihre eigene erstellen.
In diesem Leitfaden wird die Erweiterung Stream Cloud Firestore to
BigQuery (firestore-bigquery-export) als durchgehendes Beispiel verwendet. Jeder Abschnitt endet mit einem Beispiel, das zeigt, wie die Erweiterung vor der Migration aussah und wie sie nach der Migration als @firebase-function-kits/firestore-bigquery-export-Paket aussieht.
Registrieren, um weitere Informationen und Hilfe bei der Migration von Erweiterungen zu erhalten
Wenn Sie Fragen zur Migration von Firebase Extensions haben, können Sie uns unter firebase-extensions-migrator-support-external@google.com erreichen. Wir senden dieser Gruppe auch eine E-Mail, wenn wir den Leitfaden mit weiteren Informationen zum Verpacken, Testen und Verteilen Ihrer Funktionen der 2. Generation aktualisieren.
Wenn Sie dieser Gruppe beitreten möchten, senden Sie eine Nachricht an firebase-extensions-migrator-support-external+subscribe@google.com. Sie erhalten dann eine E‑Mail mit einer Beitrittsanfrage. Sie müssen auf diese E-Mail antworten und dürfen nicht auf die Schaltfläche „Dieser Gruppe beitreten“ klicken.
Hinweis
Für diese Migration benötigen Sie die folgenden Funktionen von Cloud Functions:
Parametrisierte Konfiguration: Jeder Parameter, den Sie in
extension.yamldeklarieren, wird zu einem definierten Parameter in Ihrem Paketcode.Deklarative IAM-Rollen und erforderliche APIs Jede Rolle, die Sie in
extension.yamldeklarieren, wird zu einemrequiresRole(...)-Aufruf und jede API zu einemrequiresAPI(...)-Aufruf in Ihrem Paketcode. Bei der Bereitstellung weist die Firebase-CLI dem Dienstkonto einer verwalteten Laufzeitumgebung die deklarierten Rollen zu und aktiviert die deklarierten APIs in Ihrem Namen.Lifecycle-Events für Cloud Functions-Codebases: Cloud Functions Codebases unterstützen jetzt Lebenszyklusereignisse, die Firebase Extensions ähneln. Deklarieren Sie die Einrichtung zur Installations- und Aktualisierungszeit mit den Lifecycle-Hooks
afterFirstDeploy(...)undafterRedeploy(...). Diese ersetzen dielifecycleEvents, die Sie inextension.yamldeklarieren.
Firebase Extensions-Quelle zu einer Funktion der 2. Generation migrieren
Optional: Automatisierte Migration mit dem Firebase-Agent-Skill
Sie können Schritt 1 bis 8 (Bestandsaufnahme von Ressourcen, Auslösen von Upgrades, Parameter- und Geheimniskonvertierungen, deklarative IAM, Lebenszyklushooks und Generieren der Paket-README-Datei) mit dem offiziellen extension-to-functions-codebase-KI-Agent-Skill automatisieren.
Skill installieren
Wenn Sie oder Ihr KI-Coding-Assistent (Gemini in Firebase, Cursor, Claude Code, GitHub Copilot) den Skill noch nicht installiert haben, führen Sie den folgenden Befehl mit der Skills CLI aus:
npx skills add firebase/agent-skills --skill extension-to-functions-codebase
Sobald der Skill in Ihrem Projekt installiert ist, folgt Ihr KI-Codierungsassistent automatisch den Migrationsregeln und Transformationsschritten. Sie können den folgenden Prompt verwenden:
„Migriere diese Firebase-Erweiterung bitte in ein veröffentlichbares Function Kit-Paket der 2. Generation gemäß der Anleitung im extension-to-functions-codebase-Skill.“
1. Erweiterung inventarisieren
Erstellen Sie zuerst ein Inventar Ihrer Erweiterung. Das ist eine vollständige Liste aller Elemente, die in der Erweiterung deklariert, ausgeliefert und dokumentiert werden. So hat jedes Verhalten ein definiertes Ziel in der Funktion der 2. Generation und nichts geht bei der Migration verloren.
Prüfen Sie die folgenden Punkte und notieren Sie sich, was Sie finden:
extension.yaml, in der Sie Ihre Parameter, Funktionen, Ereignisse, IAM-Rollen, erforderlichen APIs, Secrets und Lebenszyklus-Hooks deklarieren.functions/, das Ihren Funktionscode, Ihre Abhängigkeiten, die Build-Konfiguration, Trigger und Aufgabenwarteschlangenfunktionen enthält.README.md,PREINSTALL.mdundPOSTINSTALL.mdmit Einrichtungsanleitungen, Warnungen und Abrechnungshinweisen.scripts/, das alle Import-, Backfill-, IAM-, Reparatur- oder Migrationsdienstprogramme sowie alle anderen Tools enthält, die Sie zusammen mit der Erweiterung bereitstellen.
Entscheiden Sie dann für jedes Element in extension.yaml, wo es im npm-Paket platziert werden soll:
Nutzerkonfiguration in Cloud Functions-Parameter umwandeln (Schritt 4)
Konvertieren Sie die Secrets in Cloud Functions-Secrets (Schritt 4).
IAM-Rollen in
requiresRole(...)-Deklarationen umwandeln (Schritt 6)Konvertieren Sie erforderliche Google-APIs in
requiresAPI(...)-Deklarationen (Schritt 6).Installations- und Aktualisierungshooks in
afterFirstDeploy(...)- undafterRedeploy(...)-Deklarationen umwandeln (Schritt 7).Instanz-IDs von
EXT_INSTANCE_IDinFIREBASE_KIT_INSTANCE_IDkonvertieren (Schritt 4)
Beispiel:Streamen von Cloud Firestore zu BigQuery
Beim Lesen von firestore-bigquery-export/extension.yaml und functions/ wird dieses Inventar erstellt:
In „extension.yaml“ |
Anzahl / Wert | Wohin gelangen die Daten? |
|---|---|---|
params |
25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) |
Cloud Functions params (Schritt 4) |
apis |
bigquery.googleapis.com |
requiresAPI(...) (Schritt 6) |
roles |
bigquery.dataEditor, datastore.user, bigquery.user |
requiresRole(...) (Schritt 6) |
resources |
1 Ereignistrigger (fsexportbigquery) + Aufgabenwarteschlangenfunktionen (initBigQuerySync, setupBigQuerySync) |
Exportierte Paketfunktionen (Schritt 3) |
lifecycleEvents |
onInstall → initBigQuerySync; onUpdate / onConfigure → setupBigQuerySync |
afterFirstDeploy / afterRedeploy (Schritt 7) |
| Instanz-ID | Nicht verwendet (keine EXT_INSTANCE_ID-Lesevorgänge) |
Keine Daten zum Migrieren |
scripts/ |
import/ (Backfill), gen-schema-view/ |
Als Skripts beibehalten (nicht im Umfang enthalten) |
Analyse: In der Erweiterung werden keine type: secret-Parameter deklariert. Daher ist in Schritt 4 nichts für die Migration von Secrets zu tun. Der Ereignistrigger gehört bereits zur 2. Generation. Nur die Aufgabenwarteschlangen-Funktionen gehören noch zur 1. Generation (relevant in Schritt 3).
2. package.json aktualisieren
Aktualisieren Sie die package.json-Datei Ihrer Erweiterung. Wenn Sie eine Erweiterung migrieren, kann dies das Stammverzeichnis package.json sein. Wenn Sie viele Erweiterungen in einem Repository migrieren, geben Sie jeder Erweiterung ein eigenes Paket.
Mindestens erforderliche SDK-Versionen:Deklarieren Sie firebase-functions >=
7.4.0 und firebase-admin >=
14.2.0 als Abhängigkeiten. Deklarieren Sie Ihre Version von firebase-functions auch als Peer-Abhängigkeit, damit das Cloud Functions-Projekt Ihrer Nutzer dieselbe Version des SDK hat, mit der Ihre Bibliothek geschrieben wurde.
{
"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.4.0"
},
"dependencies": {
"firebase-functions": "^7.4.0",
"firebase-admin": "^14.2.0"
}
}
Beispiel:Streamen von Cloud Firestore zu BigQuery
Vorher Die functions/package.json der Erweiterung ist privat, enthält die Erweiterungs-ID und deklariert firebase-functions als direkte Abhängigkeit:
{
"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"
}
}
Nachher: Ein veröffentlichbares Paket: Name mit Bereich, eine exports-Zuordnung und firebase-functions wurde nach peerDependencies verschoben:
{
"name": "@firebase-function-kits/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.4.0"
},
"dependencies": {
"@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
"firebase-admin": "^14.2.0",
"firebase-functions": "^7.4.0"
}
}
3. Funktionen von der 1. Generation auf die 2. Generation upgraden
Wenn Ihre Erweiterung weiterhin Funktionen der 1. Generation exportiert, konvertieren Sie jeden Trigger in das entsprechende Äquivalent der 2. Generation. Importieren Sie aus den firebase-functions/...-Modulen und übergeben Sie Laufzeiteinstellungen in den Triggeroptionen.
Weitere Informationen finden Sie im Cloud Functions-Upgrade-Leitfaden der 2. Generation. Sie können den Aufwand für das Umschreiben minimieren, indem Sie die gepatchte Ereignis-Destrukturierung der 2. Generation verwenden. Außerdem müssen Sie Ihre Funktionslogik nicht umschreiben, da im SDK der 2. Generation die v1-Parameter als Felder im Ereignisobjekt verfügbar sind. So können Sie destrukturierte/benannte Parameter verwenden und Ihre Geschäftslogik unverändert lassen.
Vorher 1. Generation:
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);
});
Nachher: 2. Generation:
import { onDocumentWritten } from "firebase-functions/firestore";
export const syncV2 = onDocumentWritten(
{ document: "{collectionId}/{documentId}" },
async ({ change, context }) =>
await handleWrite(change.before, change.after, context.params)
);
Cloud Functions-Versionsvergleich – hier finden Sie eine umfassende Liste der Unterschiede zwischen Funktionen der 1. und 2. Generation.
4. Erweiterungsparameter und ‑secrets konvertieren
Parameter
Jeder Parameter, den Sie in extension.yaml deklarieren, wird zu einem Cloud Functions-Parameter.
Direkte Umgebungsvariablen lesen:
const collectionPath = process.env.COLLECTION_PATH;
in Cloud Functions-Parameter:
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);
}
);
Verwenden Sie collectionPath.value(), um den String in einem Handler zu lesen. Verwenden Sie collectionPath direkt dort, wo ein Platzhalter erwartet wird, z. B. in einem Funktionstriggerpfad.
Die Firebase CLI erkennt Ihre Parameter und liest ihre Werte aus .env, .env.<projectId> oder fordert Ihre Nutzer während der Bereitstellung auf, sie anzugeben. Behalten Sie dieselben Parameternamen bei, damit Werte aus einer vorhandenen Installation übernommen werden.
Es ist wichtig, dass Sie die in Ihrem Code deklarierten Parameternamen nicht ändern. Bei der Erweiterungsmigration bleiben vorhandene Endnutzer-Parameterwerte automatisch erhalten, aber nur, wenn die Namen unverändert sind.
Beispiel:Streamen von Cloud Firestore zu BigQuery
Vorher Ein in extension.yaml deklarierter Parameter, der in config.ts als Umgebungsvariable gelesen wird:
# extension.yaml
- param: COLLECTION_PATH
label: Collection path
type: string
required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,
Nachher: Ein defineString; die CLI erkennt es und liest aus .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, analogous to "required: true" in extension.yaml
input: { text: { nonEmpty: true } }
}),
Der Parametername hat sich nicht geändert, sodass ein vorhandener .env weiterhin funktioniert.
Instanz-ID
Erweiterungen lesen ihre Instanz-ID aus EXT_INSTANCE_ID, die von der Extensions-Laufzeitumgebung eingefügt wird. Funktionskits lesen ihre Instanz-ID aus FIREBASE_KIT_INSTANCE_ID. Die Firebase-Befehlszeilenschnittstelle legt für jede Kit-Instanz den Schlüssel der Instanz in der instances-Zuordnung in firebase.json fest. Die CLI stellt sie während der Bereitstellung, im Emulator und für die bereitgestellten Funktionen bereit.
Die Instanz-ID ist kein Parameter. Deklarieren Sie sie also nicht mit defineString. Tatsächlich ist FIREBASE_... ein reserviertes Präfix in .env-Dateien, sodass Nutzer es dort nicht festlegen oder überschreiben können. Die von der CLI eingefügten Werte sind für das Parametersystem nicht sichtbar. Lesen Sie sie direkt aus der Umgebung:
// Before
const instanceId = process.env.EXT_INSTANCE_ID;
// After
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
Die Variable wird nur festgelegt, wenn Ihr Paket als Kit bereitgestellt wird. Wenn Ihr Code auch als eigenständige Codebasis bereitgestellt wird (siehe Schritt 9), behandeln Sie ihn entweder als optional oder geben Sie schnell eine klare Fehlermeldung aus, wenn er fehlt. Wenn Ihre Erweiterung die Instanz-ID als nutzerorientierten Parameter verfügbar gemacht hat, müssen Sie diesen Parameter entfernen, da die Firebase-Befehlszeile jetzt den Wert enthält.
Beispiel: Nutzerdaten löschen
Die Erweiterung „Stream Cloud Firestore to BigQuery“ liest ihre Instanz-ID nicht, daher gibt es hier nichts zu migrieren. Die Erweiterung „Nutzerdaten löschen“ verwendet sie, um ihre Pub/Sub-Themen zu benennen.)
Vorher Als Rohumgebungsvariable in config.ts mit dem Präfix ext- lesen, das von Extensions für seine Ressourcen verwendet wird:
// functions/src/config.ts
discoveryTopic: `ext-${process.env.EXT_INSTANCE_ID}-discovery`,
deletionTopic: `ext-${process.env.EXT_INSTANCE_ID}-deletion`,
Nachher: Ein einfacher process.env-Lesevorgang von FIREBASE_KIT_INSTANCE_ID, der für zwei normale Parameter verwendet wird, damit Nutzer die Themennamen überschreiben können:
// src/config.ts
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
// Non-empty defaults so Pub/Sub trigger bindings resolve during deploy
// discovery without freezing an empty topic name into the manifest.
discoveryTopicName: defineString("DISCOVERY_TOPIC_NAME", {
default: `kit-${instanceId}-discovery`,
}),
deletionTopicName: defineString("DELETION_TOPIC_NAME", {
default: `kit-${instanceId}-deletion`,
}),
Die Standardwerte dürfen nicht leer sein, da Triggerbindungen zur Erkennungszeit aufgelöst werden. Ein leerer Standardwert würde als Themenname in das Bereitstellungsmanifest geschrieben. Das Kit ist auch defensiv gegenüber der Ausführung außerhalb des Kontexts eines Kits. Wenn die Variable fehlt, wird der Standardwert auf Modulebene zu kit-undefined-discovery ausgewertet. Der Konfigurationsladevorgang schlägt daher mit einem erklärenden Fehler fehl:
// ...
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
if (!instanceId) {
throw new Error(
"FIREBASE_KIT_INSTANCE_ID is not set. It is provided automatically to " +
"kit instances by firebase-tools >= 15.32.0; deploy or emulate this " +
"kit with a supported CLI version."
);
}
// ...
Diese Prüfung wird ausgeführt, wenn ein Handler seine Konfiguration zum ersten Mal auflöst. Eine fehlende Variable führt also zu einem eindeutigen Laufzeitfehler und nicht dazu, dass Funktionen stillschweigend an kit-undefined-*-Themen gebunden werden. Wenn Sie den Bereitstellungsvorgang selbst ablehnen möchten, führen Sie den Check im Modulbereich aus, damit er während der Erkennung ausgeführt wird. Da die CLI die Instanz-ID aus firebase.json ableitet, gibt es keine konfigurierbare INSTANCE_ID und nichts, was über mehrere Instanzen hinweg synchronisiert werden muss.
Secrets
In extension.yaml deklarieren Sie Secrets mit type: secret. Die Extensions-Laufzeit speichert und bindet sie, sodass Ihr Erweiterungscode process.env.PARAM_NAME direkt lesen kann. In einer typischen Cloud Functions-Codebasis deklarieren und binden Sie jedes Secret explizit:
import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";
const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);
Nachdem Ihre Erweiterung zu einem npm-Paket/Kit migriert wurde, werden geheime Referenzen in der .env-Datei des Endnutzers verwaltet. Es ist wichtig, dass Sie die in Ihrem Code deklarierten Namen der Secrets nicht
ändern. Während der Migration werden die Secrets der Endnutzer entsprechend migriert.
Beispiel:E-Mail über Cloud Firestore auslösen
Vorher MAIL_COLLECTION und SMTP_PASSWORD werden in config.ts als Rohumgebungsvariablen gelesen:
# 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,
Nachher: Ein defineString und ein defineSecret. Das CLI erkennt beide und liest aus .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();
// ...
}
);
5. Interne Aufgabenwarteschlangenaufrufe migrieren
Einige Erweiterungen stellen Aufgaben in ihre eigenen Aufgabenwarteschlangen aus ihrem Funktionscode ein, indem sie Firebase Admin SDK verwenden. Das ist etwas anderes als das Empfangen einer zugewiesenen Aufgabe (siehe die Abschnitte Funktionen aktualisieren und Convert lifecycle hooks). Hier ist Ihr Code der Producer, der queue.enqueue(...) aufruft.
In früheren Versionen von Admin SDK mussten Erweiterungen ihre eigene Erweiterungsinstanz-ID als zweiten Parameter übergeben, um eine Task Queue-Funktion in derselben Erweiterung aufzurufen. Ab firebase-admin 14.2.0 ist dies weder erforderlich noch empfehlenswert. Die Task Queue API zielt jetzt standardmäßig auf Aufgabenwarteschlangen im selben Kontext ab (z. B. eine Erweiterung oder ein Kit). Sie können diesen Parameter in Ihrem Code sowohl als Erweiterung als auch als eigenständige Funktion entfernen.
Durch das Entfernen dieses Parameters wird die Portierbarkeit und Vorwärtskompatibilität sichergestellt.
Alles andere am Enqueue-Aufruf – der locations/<region>/functions/<name>-Ressourcenpfad, die Aufgaben-Payload und Ihre Wiederholungslogik – bleibt gleich.
Weitere Informationen zum Einreihen von Funktionen mit Cloud Tasks finden Sie unter Funktionen mit Cloud Tasks in die Warteschlange stellen.
Vorher Erweiterung der 1. Generation:
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);
Nachher: Verlängerung der 2. Generation:
import { getFunctions } from "firebase-admin/functions";
const queue = getFunctions().taskQueue(
`locations/${process.env.FUNCTION_REGION}/functions/syncBigQuery`
);
await queue.enqueue(taskData);
Wenn Ihr Enqueue-Aufruf auf eine mit einem Präfix versehene Codebasis ausgerichtet ist, wird auch der ermittelte Funktionsname mit einem Präfix versehen (z. B. orders-syncBigQuery). Weitere Informationen finden Sie unter Ersatz-Funktionskit-Instanz prüfen und installieren und Als Funktionskit testen.
6. Erforderliche APIs und IAM-Rollen deklarieren
Verschieben Sie die IAM- und API-Anforderungen Ihrer Erweiterung aus extension.yaml in den Code:
import { requiresAPI, requiresRole } from "firebase-functions";
requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");
Bei der deklarativen Sicherheit wird mit der Firebase CLI ein verwaltetes Laufzeit-Dienstkonto für die Codebasis erstellt oder aktualisiert und ihm werden alle deklarierten Rollen zugewiesen. Dokumentieren Sie für Ihre Nutzer, dass alle Funktionen in der Codebasis mit diesen Rollen ausgeführt werden, sofern die endgültige API kein eingeschränkteres Modell unterstützt.
Beispiel:Streamen von Cloud Firestore zu BigQuery
Vorher In extension.yaml deklariert; die Extensions-Laufzeit hat die API aktiviert und einem verwalteten Konto die Rollen zugewiesen:
apis:
- apiName: bigquery.googleapis.com
roles:
- role: bigquery.dataEditor
- role: datastore.user
- role: bigquery.user
Nachher: Im Code mit requiresAPI und requiresRole deklariert:
import { requiresAPI, requiresRole } from "firebase-functions";
requiresAPI(
"bigquery.googleapis.com",
"Needed to write changelog rows and views"
);
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/datastore.user");
requiresRole("roles/bigquery.user");
7. Convert-Lebenszyklus-Hooks
Wenn Ihre Erweiterung getExtensions().runtime() aufruft (z. B. setProcessingState oder setFatalError), löschen Sie diese Aufrufe, da sie einen Fehler auslösen, wenn sie von einer normal bereitgestellten Funktion der 2. Generation aufgerufen werden. Der Lebenszyklusstatus wird jetzt durch afterFirstDeploy und afterRedeploy bestimmt. Die Statusverfolgung wird nicht verwendet.
Firebase Extensions kann die Einrichtung ausführen, wenn ein Nutzer eine Erweiterung installiert, aktualisiert oder neu konfiguriert. Deklarieren Sie im npm-Paket entsprechende Lebenszyklusaktionen im Code.
Einmalige Einrichtung:
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: {}
}
});
Für Konfigurations- oder Code-Updates:
import { afterRedeploy } from "firebase-functions/lifecycle";
afterRedeploy({
task: {
function: "runInitialSetup",
body: { reconcile: true }
}
});
Machen Sie Ihre Lebenszyklusaktionen idempotent. Wenn das Senden oder die Ausführung fehlschlägt, müssen Ihre Nutzer sie möglicherweise manuell noch einmal ausführen:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME
Beispiel:Streamen von Cloud Firestore zu BigQuery
Vorher lifecycleEvents in extension.yaml, aufgrund der Extensions-Laufzeit:
lifecycleEvents:
onInstall:
function: initBigQuerySync
processingMessage: Configuring BigQuery Sync.
onUpdate:
function: setupBigQuerySync
processingMessage: Configuring BigQuery Sync
onConfigure:
function: setupBigQuerySync
processingMessage: Configuring BigQuery Sync
Nachher: Im Code deklariert; die Aufgabenbereitstellung BigQuery bei der ersten Bereitstellung:
import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";
afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });
Die Bereitstellung ist idempotent. Bei einem erneuten Ausführen werden Dataset, Tabelle und Ansichten abgeglichen.
Nutzer können sie mit firebase functions:lifecycle:run afterFirstDeploy
CODEBASE_NAME manuell noch einmal ausführen.
8. Dokumenteinrichtung für Ihre Nutzer
Schreiben Sie ein Paket README, in dem mindestens Folgendes erklärt wird:
- Die
.env-Werte, die für das Paket erforderlich sind. - Die Secrets, die für das Paket erforderlich sind, und wie vorhandene Secret-Werte migriert werden.
- Die IAM-Rollen, die das Paket mit
requiresRole(...)deklariert. - Die Google APIs, die durch das Paket aktiviert werden oder für die das Paket erforderlich ist.
- Die vom Paket deklarierten Lebenszyklus-Hooks und wie sie manuell noch einmal ausgeführt werden.
- Abrechnungshinweise.
- Was hat sich im Vergleich zur ursprünglichen Erweiterung geändert?
- Wie das Paket seine Instanz-ID erhält (
FIREBASE_KIT_INSTANCE_ID, die von der CLI festgelegt wird) und dass alle Funktionen der Instanz mit dem Präfixkit-<instanceId>-bereitgestellt werden.
Beispiel:Streamen von Cloud Firestore zu BigQuery
Das Paket README enthält eine konkrete Tabelle mit den Änderungen:
| Bedenken | Als Erweiterung | Als @firebase-function-kits/firestore-bigquery-export |
|---|---|---|
| Konfiguration | Erweiterungsparameter | Cloud Functions-Parameter über .env |
| IAM | Durch Erweiterungen gewährt | requiresRole(...), bei der Bereitstellung angewendet |
| Wird bereitgestellt | Lifecycle-Aufgabe nach Erweiterungen | afterFirstDeploy / afterRedeploy Aufgabe |
| Funktionsnamen | ext-<instanceId>-fsexportbigquery |
fsexportbigquery (optionales Präfix) |
| Instanz-ID | EXT_INSTANCE_ID, die von Erweiterungen eingefügt wurden |
FIREBASE_KIT_INSTANCE_ID, die von der CLI aus firebase.json festgelegt wird |
9. Funktion der 2. Generation testen
Sie sollten jetzt eine Funktion der 2. Generation haben, die sich bei der Bereitstellung identisch mit einer Neuinstallation Ihrer Erweiterung verhält. Im nächsten Schritt müssen Sie alle Probleme beheben, die versehentlich aufgetreten sind.
Wenn Sie setGlobalOptions aufrufen möchten, um globale Optionen wie eine Standardregion oder CPU festzulegen, müssen Sie dies nur tun, wenn Sie Ihr Kit als eigenständige Funktion der 2. Generation bereitstellen. Wenn Ihr Kit als npm-Paket installiert ist, rufen Ihre Nutzer setGlobalOptions in ihrem Wrapping-Code auf, um diese Parameter zu konfigurieren. Wenn dies zweimal geschieht, erhalten sie eine Warnung.
Sie können diesen Aufruf schützen, indem Sie die Umgebungsvariable FIREBASE_KIT_INSTANCE_ID prüfen:
import { setGlobalOptions } from "firebase-functions";
if (!process.env.FIREBASE_KIT_INSTANCE_ID) {
setGlobalOptions({
region: "us-east1",
maxInstances: 10,
});
}
Achten Sie darauf, dass Sie firebase-tools
>= 15.32.0 verwenden, und stellen Sie die konvertierte Funktion der 2. Generation in einem Testprojekt mit den entsprechenden Ressourcen bereit, um ihr Verhalten zu testen. Wenn Sie bereits ein Testprojekt eingerichtet haben, um Ihre Erweiterung zu testen, führen Sie den folgenden Befehl aus:
firebase deploy --only functions
Füllen Sie den resultierenden Assistenten aus und geben Sie die Parameterwerte so ein, wie Sie das Installationsformular in der Firebase-Konsole für die Erweiterung ausgefüllt hätten.
Beispiel:Streamen von Cloud Firestore zu BigQuery
Wir prüfen die Synchronisierung von Cloud Firestore zu BigQuery von Anfang bis Ende:
- Erstellen Sie auf der Seite Cloud Firestore der Firebase-Konsole die Sammlung, die Sie als
COLLECTION_PATH(users) festgelegt haben, falls sie noch nicht vorhanden ist. - Erstellen Sie ein Dokument mit dem Namen
bigquery-mirror-test, das beliebige Felder mit beliebigen Werten enthält. Fragen Sie auf der Seite BigQuery der Google Cloud-Console die Rohdaten-Changelog-Tabelle ab. Es sollte eine einzelne Zeile mit dem Protokoll der Dokumenterstellung enthalten:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`Fragen Sie die letzte Ansicht ab. Diese sollte das letzte Änderungsereignis für das einzige vorhandene Dokument (
bigquery-mirror-test) zurückgeben:SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`Löschen Sie das Dokument
bigquery-mirror-testin Cloud Firestore. Sie verschwindet aus der Ansicht „Letzte Änderungen“ und der Rohdaten-Changelog-Tabelle wird einDELETE-Ereignis hinzugefügt.Mit dem folgenden Befehl können Sie den vollständigen Verlauf eines einzelnen Dokuments aufrufen:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog` WHERE document_name = "bigquery-mirror-test" ORDER BY timestamp ASC
Unterschiede zum Testen der Erweiterung:
- Der Trigger wird als
fsexportbigquerybereitgestellt (kein Präfix, wenn er als typische Funktion der 2. Generation und nicht als Kit bereitgestellt wird), nicht alsext-<instanceId>-fsexportbigquery. Suchen Sie im Dashboard und in den Logs von Cloud Functions nach diesem Namen. - Ihr Code wird jetzt in der Firebase Local Emulator Suite als normale Funktionen ausgeführt.
Mit
.env.localkönnen Sie den Wert von Parametern festlegen, die im Emulator verwendet werden sollen. Sie können Ihren Code auch mit demfirebase-functions-testSDK testen, wie unter Unittests für Cloud Functions beschrieben. - Die Bereitstellung erfolgt nicht mehr über die Extensions-Laufzeit. Wenn die Changelog-Tabelle nach der Bereitstellung fehlt, führen Sie die Einrichtungsaufgabe manuell noch einmal aus:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. Der Task ist idempotent. Wenn Sie ihn also noch einmal ausführen, werden Dataset, Tabelle und Ansichten abgeglichen. - Parameterwerte stammen aus
.envund nicht aus dem Installationsformular. Daher sind Wiederholungen vonfirebase deploynicht interaktiv, sobald.envabgeschlossen ist.
10. Funktions-Kit auf npm veröffentlichen
Nachdem Sie die Konvertierung Ihrer Erweiterung in eine Funktion der 2. Generation validiert haben, können Sie einen Release-Kandidaten für End-to-End-Tests in npm veröffentlichen. Verwenden Sie dazu eine der folgenden Anleitungen:
- Öffentliche Pakete ohne Bereich erstellen und veröffentlichen
- Öffentliche Pakete mit Bereich erstellen und veröffentlichen
Wenn Ihr Kit in npm veröffentlicht wird, kann es mit firebase functions:kits:install installiert und als offizieller Ersatz für Ihre Erweiterung aufgeführt werden.
Wir empfehlen dringend, zuerst einen Release-Kandidaten zu veröffentlichen. Kits werden nach Paketname und ‑version installiert. Mit einer Vorabversion können Sie den tatsächlichen Installationsablauf anhand der Registrierung testen, ohne ein unfertiges Paket für Nutzer freizugeben, die mit dem Standardtag latest installieren.
Vor der Veröffentlichung:
- Wählen Sie einen Paketnamen aus. Sowohl Namen mit als auch ohne Bereich funktionieren (siehe die Anleitungen oben). Beachten Sie, dass Pakete mit Bereich standardmäßig privat sind. Übergeben Sie daher
--access public. - Baue und prüfe, welche Schiffe.
mainundtypesverweisen auf die kompilierte Ausgabe (lib/in unserem Beispiel), daher muss dieses Verzeichnis in der veröffentlichten TAR-Datei enthalten sein. Verwenden Sie.npmignoreoder einefiles-Zulassungsliste und prüfen Sie das Ergebnis mitnpm pack --dry-run. EinprepublishOnly-Script, das Ihren Build ausführt, verhindert die Veröffentlichung veralteter Ausgaben.
package.json-Ergänzungen, die die Veröffentlichung standardmäßig sicher machen:
{
"files": ["lib", "README.md", "CHANGELOG.md"],
"publishConfig": { "access": "public", "tag": "next" },
"scripts": {
"build": "tsc -b",
"prepublishOnly": "npm run build && npm test"
}
}
Das Feld "publishConfig": { "tag": "next" } sorgt dafür, dass ein einfacher npm
publish nie latest überschreibt.
Releasekandidat erstellen:
Wenn Sie beispielsweise die Version lokal von 0.0.2-rc.3 auf 0.0.2-rc.4 erhöhen möchten (dabei werden Commits und Tags in Git ausgeführt, wenn sich package.json im Repository-Root befindet):
npm version prerelease --preid rc
So veröffentlichen Sie den Releasekandidaten und registrieren @your-org/your-kit@0.0.2-rc.4 auf npm unter dem Tag next:
npm publish
Es kann einige Minuten dauern, bis die neue Version auf der npm-Website angezeigt wird. npm view liest die Registrierung direkt:
npm view @your-org/your-kit versions dist-tags
Sobald Schritt 11 und Schritt 12 dieses Leitfadens abgeschlossen sind, können Sie das Paket auf eine stabile Version hochstufen:
npm version 0.0.2
npm publish --tag latest
npm dist-tag add @your-org/your-kit@0.0.2 next
Hinweis zu npm-shrinkwrap.json:Wir empfehlen dringend, eine npm-shrinkwrap.json-Datei in Ihr Paket aufzunehmen. Andernfalls werden Nutzer bei der Installation von der CLI gewarnt. So wird sichergestellt, dass Nutzer genau die Abhängigkeiten verwenden, mit denen Sie getestet haben, und es wird dazu beigetragen, Angriffe auf die Lieferkette zu verhindern. Die Shrinkwrap-Datei wird jedoch unverändert in die Projekte Ihrer Nutzer übernommen, auch während des Cloud Functions-Builds (npm ci), bei dem Einträge, die nur für die Entwicklung bestimmt sind, mit EBADPLATFORM fehlschlagen können. Möglicherweise müssen Sie "dev": true-Einträge und devDependencies aus der veröffentlichten Shrinkwrap-Kopie entfernen.
Beispiel:Streamen von Cloud Firestore zu BigQuery
Das package.json des Kits zum Zeitpunkt des vierten Releasekandidaten:
{
"name": "@firebase-function-kits/firestore-bigquery-export",
"version": "0.0.2-rc.4",
"repository": {
"type": "git",
"url": "https://github.com/firebase/extensions.git",
"directory": "kits/firestore-bigquery-export"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"engines": { "node": "22" },
"scripts": { "build": "tsc -b" }
}
In diesem Fall befindet sich das Kit in einem Monorepo. Daher ist es wichtig, repository.directory für den Link zur npm-Registrierung anzugeben, damit auf den richtigen Ordner verwiesen wird. In CHANGELOG.md werden Notizen für die anstehende Veröffentlichung gespeichert.
11. Als Funktions-Kit testen
Nachdem Sie Ihr Kit veröffentlicht haben, empfehlen wir, es mit npm zu testen.
Achten Sie darauf, dass Sie die Version >= 15.32.0 von firebase-tools verwenden, und installieren Sie das Kit:
firebase functions:kits:install --package <your-package-name>@<your-prerelease-version>
Dadurch wird Ihr Paket von npm heruntergeladen, in einem neuen Quellverzeichnis für Ihr Kit eingerichtet und Sie werden durch die Konfiguration der ersten Instanz geführt, ähnlich wie beim Installationsvorgang für Erweiterungen. Nachdem Sie Ihr Paket lokal installiert und eingerichtet haben, führen Sie einen Bereitstellungsvorgang aus, um die Ressourcen in Ihrem Google Cloud-Projekt zu erstellen:
firebase deploy --only functions:<your-kit-instance-id>
Nach der Installation gibt die Firebase-CLI einen ähnlichen Bereitstellungsbefehl mit der genauen Instanz-ID aus, die Sie bei der Installation ausgewählt haben.
Validieren Sie das Kit noch einmal anhand der Anleitung in
Schritt 9. Funktion der 2. Generation testen Da Sie jetzt Kits für die Bereitstellung verwenden, haben Ihre Funktionen das Präfix kit-<instance-id>-<method-name>. So können Kits mehrere Instanzen haben und dieselbe Funktion mehrmals in einem Projekt bereitstellen, jeweils mit einem eindeutigen Namen.
12. Ersatz für Migration testen
Sie können eine funktionierende Erweiterungsinstanz einrichten und dann die Anleitung zur Nutzermigration (entweder mit firebase ext:migrate --package oder den CLI-Befehlen für Funktions-Kits) verwenden, um das Testen Ihres Funktions-Kits als Migrationsersatz abzuschließen.
13. Nutzer und Google über die offizielle Erweiterung informieren
Sobald Ihr Ersatz für das Funktions-Kit fertig ist und als npm-Paket verfügbar ist, zu dem Nutzer migrieren sollten, informieren Sie sowohl Ihre Nutzer als auch Google über diesen offiziellen Ersatz. Aktualisieren Sie die Datei README.md im GitHub-Repository, in dem Ihre Erweiterung gehostet wird, mit den folgenden Informationen:
<!-- FIREBASE_EXTENSION_REPLACEMENT: extension="<your-extesion-id>" package="<your-npm-package-name>" -->
> [!WARNING]
> **Deprecation Notice:** The Firebase Extension `<your-extension>` is deprecated. Migrate to the [<your-npm-package-name>](<link-to-your-npm-package>) package.
Google scannt bekannte README-Dateien von Erweiterungen nach Kommentaren wie <!--
FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export"
package="@firebase-function-kits/firestore-bigquery-export" --> und verwendet diese, um unser offizielles Register der Ersetzungen zu füllen, das im Repository firebase-tools als replacements.json gespeichert ist.
Unter replacements.json können Sie auch nachsehen, welche README.md für Ihre Erweiterung gescannt werden. Die offizielle Liste der Ersetzungen wird wöchentlich aktualisiert.
Beispiel:Streamen von Cloud Firestore zu BigQuery
Die firestore-bigquery-export-Erweiterung README.md enthält:
<!-- FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export" package="@firebase-function-kits/firestore-bigquery-export" -->
> [!WARNING]
> **Deprecation Notice:** The Firebase Extension `firebase/firestore-bigquery-export` is deprecated. Please migrate to the [`@firebase-function-kits/firestore-bigquery-export`](https://www.npmjs.com/package/@firebase-function-kits/firestore-bigquery-export) package.