Auf dieser Seite werden die Schritte zum Erstellen einer einfachen Firebase-Erweiterung beschrieben, die Sie in Ihren Projekten installieren oder für andere freigeben können. In diesem einfachen Beispiel für eine Firebase-Erweiterung werden Nachrichten in Ihrer Realtime Database überwacht und in Großbuchstaben umgewandelt.
1. Umgebung einrichten und Projekt initialisieren
Bevor Sie mit dem Erstellen einer Erweiterung beginnen können, müssen Sie eine Buildumgebung mit den erforderlichen Tools einrichten.
Installieren Sie Node.js 16 oder höher. Eine Möglichkeit zur Installation von Node ist die Verwendung von nvm (oder nvm-windows).
Installieren Sie die Firebase CLI oder aktualisieren Sie sie auf die neueste Version. Führen Sie den folgenden Befehl aus, um
npm
zu installieren oder zu aktualisieren:npm install -g firebase-tools
Initialisieren Sie nun mit der Firebase CLI ein neues Erweiterungsprojekt:
Erstellen Sie ein Verzeichnis für Ihre Erweiterung und
cd
darin:mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
Führen Sie den Befehl
ext:dev:init
der Firebase CLI aus:firebase ext:dev:init
Wählen Sie auf Aufforderung JavaScript als Sprache für Funktionen aus. Sie können aber auch TypeScript verwenden, wenn Sie Ihre eigene Erweiterung entwickeln. Antworten Sie auf die Aufforderung zur Installation von Abhängigkeiten mit „Ja“. Übernehmen Sie für alle anderen Optionen die Standardeinstellungen. Mit diesem Befehl wird eine Skelett-Codebasis für eine neue Erweiterung eingerichtet, auf der Sie mit der Entwicklung Ihrer Erweiterung beginnen können.
2. Beispielerweiterung mit dem Emulator testen
Als die Firebase CLI das neue Verzeichnis „extensions“ initialisiert hat, wurden eine einfache Beispielfunktion und ein integration-tests
-Verzeichnis erstellt, das die Dateien enthält, die zum Ausführen einer Erweiterung mit der Firebase-Emulator-Suite erforderlich sind.
Führen Sie die Beispielerweiterung im Emulator aus:
Wechseln Sie in das Verzeichnis
integration-tests
:cd functions/integration-tests
Starten Sie den Emulator mit einem Demoprojekt:
firebase emulators:start --project=demo-test
Der Emulator lädt die Erweiterung in ein vordefiniertes „Dummy“-Projekt (
demo-test
) hoch. Die Erweiterung besteht bisher aus einer einzigen HTTP-ausgelösten Funktion,greetTheWorld
, die beim Zugriff die Nachricht „Hallo Welt“ zurückgibt.Testen Sie die
greetTheWorld
-Funktion der Erweiterung, während der Emulator noch läuft. Rufen Sie dazu die URL auf, die beim Starten der Erweiterung ausgegeben wurde.In Ihrem Browser wird die Meldung „Hello World from greet-the-world“ angezeigt.
Der Quellcode für diese Funktion befindet sich im Verzeichnis
functions
der Erweiterung. Öffnen Sie die Quelle im Editor oder in der IDE Ihrer Wahl:functions/index.js
const functions = require("firebase-functions/v1"); exports.greetTheWorld = functions.https.onRequest((req, res) => { // Here we reference a user-provided parameter // (its value is provided by the user during installation) const consumerProvidedGreeting = process.env.GREETING; // And here we reference an auto-populated parameter // (its value is provided by Firebase after installation) const instanceId = process.env.EXT_INSTANCE_ID; const greeting = `${consumerProvidedGreeting} World from ${instanceId}`; res.send(greeting); });
Solange der Emulator ausgeführt wird, werden alle Änderungen, die Sie an Ihrem Functions-Code vornehmen, automatisch neu geladen. Nehmen Sie eine kleine Änderung an der
greetTheWorld
-Funktion vor:functions/index.js
const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
Speichern Sie die Änderungen. Der Emulator lädt Ihren Code neu. Wenn Sie jetzt die Funktions-URL aufrufen, wird die aktualisierte Begrüßung angezeigt.
3. Grundlegende Informationen zu „extension.yaml“ hinzufügen
Nachdem Sie eine Entwicklungsumgebung eingerichtet und den Erweiterungsemulator gestartet haben, können Sie mit dem Erstellen Ihrer eigenen Erweiterung beginnen.
Bearbeiten Sie als ersten Schritt die vordefinierten Erweiterungsmetadaten, damit sie die gewünschte Erweiterung statt greet-the-world
widerspiegeln. Diese Metadaten werden in der Datei extension.yaml
gespeichert.
Öffnen Sie
extension.yaml
in Ihrem Editor und ersetzen Sie den gesamten Inhalt der Datei durch Folgendes:name: rtdb-uppercase-messages version: 0.0.1 specVersion: v1beta # Firebase Extensions specification version; don't change # Friendly display name for your extension (~3-5 words) displayName: Convert messages to upper case # Brief description of the task your extension performs (~1 sentence) description: >- Converts messages in RTDB to upper case author: authorName: Your Name url: https://your-site.example.com license: Apache-2.0 # Required license # Public URL for the source code of your extension sourceUrl: https://github.com/your-name/your-repo
Beachten Sie die Benennungskonvention im Feld
name
: Offizielle Firebase-Erweiterungen haben ein Präfix, das das primäre Firebase-Produkt angibt, für das die Erweiterung verwendet wird, gefolgt von einer Beschreibung der Funktion der Erweiterung. Sie sollten dieselbe Konvention in Ihren eigenen Erweiterungen verwenden.Da Sie den Namen Ihrer Erweiterung geändert haben, sollten Sie auch die Emulatorkonfiguration mit dem neuen Namen aktualisieren:
- Ändern Sie in
functions/integration-tests/firebase.json
den Wertgreet-the-world
inrtdb-uppercase-messages
. - Benennen Sie
functions/integration-tests/extensions/greet-the-world.env
infunctions/integration-tests/extensions/rtdb-uppercase-messages.env
um.
- Ändern Sie in
In Ihrem Erweiterungscode sind noch einige Überreste der greet-the-world
-Erweiterung vorhanden. Lassen Sie sie vorerst. Sie aktualisieren diese in den nächsten Abschnitten.
4. Cloud-Funktion schreiben und als Erweiterungsressource deklarieren
Jetzt können Sie mit dem Schreiben von Code beginnen. In diesem Schritt schreiben Sie eine Cloud Function, die die Hauptaufgabe Ihrer Erweiterung ausführt, nämlich in Ihrer Realtime Database nach Nachrichten zu suchen und sie in Großbuchstaben zu konvertieren.
Öffnen Sie die Quelle für die Funktionen der Erweiterung (im
functions
-Verzeichnis der Erweiterung) im Editor oder in der IDE Ihrer Wahl. Ersetzen Sie den Inhalt durch Folgendes:functions/index.js
import { database, logger } from "firebase-functions/v1"; const app = initializeApp(); // Listens for new messages added to /messages/{pushId}/original and creates an // uppercase version of the message to /messages/{pushId}/uppercase // for all databases in 'us-central1' export const makeuppercase = database .ref("/messages/{pushId}/uppercase") .onCreate(async (snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); // Convert it to upper case. logger.log("Uppercasing", context.params.pushId, original); const uppercase = original.toUpperCase(); // Setting an "uppercase" sibling in the Realtime Database. const upperRef = snapshot.ref.parent.child("upper"); await upperRef.set(uppercase); });
Die alte Funktion, die Sie ersetzt haben, war eine HTTP-ausgelöste Funktion, die ausgeführt wurde, wenn auf einen HTTP-Endpunkt zugegriffen wurde. Die neue Funktion wird durch Echtzeit-Datenbankereignisse ausgelöst: Sie prüft, ob neue Elemente an einem bestimmten Pfad vorhanden sind, und schreibt bei einem positiven Ergebnis die Großbuchstabenversion des Werts zurück in die Datenbank.
In dieser neuen Datei wird übrigens die ECMAScript-Modulsyntax (
import
undexport
) anstelle von CommonJS (require
) verwendet. Wenn Sie ES-Module in Node verwenden möchten, geben Sie"type": "module"
infunctions/package.json
an:{ "name": "rtdb-uppercase-messages", "main": "index.js", "type": "module", … }
Jede Funktion in Ihrer Erweiterung muss in der Datei
extension.yaml
deklariert werden. In der Beispielerweiterung wurdegreetTheWorld
als einzige Cloud-Funktion der Erweiterung deklariert. Da Sie sie jetzt durchmakeuppercase
ersetzt haben, müssen Sie auch die Deklaration aktualisieren.Öffnen Sie
extension.yaml
und fügen Sie einresources
-Feld hinzu:resources: - name: makeuppercase type: firebaseextensions.v1beta.function properties: eventTrigger: eventType: providers/google.firebase.database/eventTypes/ref.create # DATABASE_INSTANCE (project's default instance) is an auto-populated # parameter value. You can also specify an instance. resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original runtime: "nodejs18"
Da Ihre Erweiterung jetzt Realtime Database als Trigger verwendet, müssen Sie die Emulatorkonfiguration aktualisieren, damit der RTDB-Emulator zusammen mit dem Cloud Functions-Emulator ausgeführt wird:
Wenn der Emulator noch ausgeführt wird, beenden Sie ihn mit Strg + C.
Führen Sie im Verzeichnis
functions/integration-tests
den folgenden Befehl aus:firebase init emulators
Überspringen Sie bei Aufforderung die Einrichtung eines Standardprojekts und wählen Sie dann die Funktionen und Datenbankemulatoren aus. Akzeptieren Sie die Standardports und erlauben Sie dem Einrichtungstool, alle erforderlichen Dateien herunterzuladen.
Starten Sie den Emulator neu:
firebase emulators:start --project=demo-test
Testen Sie die aktualisierte Erweiterung:
Öffnen Sie die Benutzeroberfläche des Datenbankemulators über den Link, den der Emulator beim Starten ausgegeben hat.
Bearbeiten Sie den Stammknoten der Datenbank:
- Feld:
messages
- Typ:
json
- Wert:
{"11": {"original": "recipe"}}
Wenn alles richtig eingerichtet ist, sollte beim Speichern Ihrer Datenbankänderungen die
makeuppercase
-Funktion der Erweiterung ausgelöst werden und Nachricht 11 einen untergeordneten Eintrag mit dem Inhalt"upper": "RECIPE"
hinzufügen. Sehen Sie sich die Protokolle und die Datenbank-Tabs der Emulator-Benutzeroberfläche an, um die erwarteten Ergebnisse zu bestätigen.- Feld:
Fügen Sie dem Knoten
messages
({"original":"any text"}
) weitere untergeordnete Elemente hinzu. Wenn Sie einen neuen Eintrag hinzufügen, sollte die Erweiterung einuppercase
-Feld mit dem in Großbuchstaben geschriebenen Inhalt desoriginal
-Felds hinzufügen.
Sie haben jetzt eine vollständige, aber einfache Erweiterung, die auf einer RTDB-Instanz ausgeführt wird. In den folgenden Abschnitten optimieren Sie diese Erweiterung mit einigen zusätzlichen Funktionen. Anschließend bereiten Sie die Erweiterung für den Vertrieb vor und erfahren, wie Sie sie im Erweiterungs-Hub veröffentlichen.
5. APIs und Rollen deklarieren
Firebase gewährt jeder Instanz einer installierten Erweiterung über ein pro Instanz erstelltes Dienstkonto eingeschränkten Zugriff auf das Projekt und seine Daten. Jedes Konto hat die Mindestberechtigungen, die für die Funktion erforderlich sind. Aus diesem Grund müssen Sie alle IAM-Rollen, die für Ihre Erweiterung erforderlich sind, explizit angeben. Wenn Nutzer Ihre Erweiterung installieren, erstellt Firebase ein Dienstkonto mit diesen Rollen und verwendet es, um die Erweiterung auszuführen.
Sie müssen keine Rollen deklarieren, um Ereignisse eines Produkts auszulösen. Sie müssen jedoch eine Rolle deklarieren, um anderweitig damit zu interagieren. Da die im letzten Schritt hinzugefügte Funktion in die Realtime Database schreibt, müssen Sie extension.yaml
die folgende Deklaration hinzufügen:
roles:
- role: firebasedatabase.admin
reason: Allows the extension to write to RTDB.
Ebenso deklarieren Sie die Google APIs, die von einer Erweiterung verwendet werden, im Feld apis
. Wenn Nutzer Ihre Erweiterung installieren, werden sie gefragt, ob sie diese APIs automatisch für ihr Projekt aktivieren möchten. Dies ist in der Regel nur für nicht Firebase-spezifische Google APIs erforderlich und in diesem Leitfaden nicht erforderlich.
6. Vom Nutzer konfigurierbare Parameter definieren
Die Funktion, die Sie in den letzten beiden Schritten erstellt haben, hat an einem bestimmten RTDB-Speicherort nach eingehenden Nachrichten gesucht. Manchmal ist es aber tatsächlich sinnvoll, einen bestimmten Speicherort zu beobachten, z. B. wenn Ihre Erweiterung auf einer Datenbankstruktur basiert, die Sie ausschließlich für Ihre Erweiterung verwenden. In den meisten Fällen sollten Sie diese Werte jedoch von Nutzern konfigurierbar machen, die Ihre Erweiterung in ihren Projekten installieren. So können Nutzer Ihre Erweiterung mit ihrer vorhandenen Datenbankkonfiguration verwenden.
Den Pfad, in dem die Erweiterung nach neuen Nachrichten sucht, für Nutzer konfigurierbar machen:
Fügen Sie in der Datei
extension.yaml
einen Abschnittparams
hinzu:- param: MESSAGE_PATH label: Message path description: >- What is the path at which the original text of a message can be found? type: string default: /messages/{pushId}/original required: true immutable: false
Dadurch wird ein neuer Stringparameter definiert, den Nutzer beim Installieren Ihrer Erweiterung festlegen müssen.
Gehen Sie in der Datei
extension.yaml
zurück zurmakeuppercase
-Erklärung und ändern Sie das Feldresource
in Folgendes:resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
Das
${param:MESSAGE_PATH}
-Token ist ein Verweis auf den Parameter, den Sie gerade definiert haben. Wenn Ihre Erweiterung ausgeführt wird, wird dieses Token durch den Wert ersetzt, den der Nutzer für diesen Parameter konfiguriert hat. Die Funktionmakeuppercase
überwacht dann den vom Nutzer angegebenen Pfad. Mit dieser Syntax können Sie überall inextension.yaml
(und inPOSTINSTALL.md
– dazu später mehr) auf benutzerdefinierte Parameter verweisen.Sie können auch über den Code Ihrer Funktionen auf benutzerdefinierte Parameter zugreifen.
In der Funktion, die Sie im letzten Abschnitt geschrieben haben, haben Sie den Pfad, auf den Sie achten möchten, hartcodiert. Ändern Sie die Triggerdefinition so, dass sie stattdessen auf den benutzerdefinierten Wert verweist:
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
Bei Firebase-Erweiterungen dient diese Änderung nur der Dokumentation: Wenn eine Cloud-Funktion als Teil einer Erweiterung bereitgestellt wird, wird die Triggerdefinition aus der Datei
extension.yaml
verwendet und der in der Funktionsdefinition angegebene Wert ignoriert. Es empfiehlt sich jedoch, in Ihrem Code zu dokumentieren, woher dieser Wert stammt.Es mag enttäuschend sein, eine Codeänderung vorzunehmen, die keine Auswirkungen auf die Laufzeit hat. Wichtig ist jedoch, dass Sie in Ihrem Funktionscode auf jeden benutzerdefinierten Parameter zugreifen und ihn als normalen Wert in der Logik der Funktion verwenden können. Fügen Sie als Hinweis auf diese Funktion die folgende Protokollanweisung hinzu, um zu zeigen, dass Sie tatsächlich auf den vom Nutzer definierten Wert zugreifen:
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate( async (snapshot, context) => { logger.log("Found new message at ", snapshot.ref); // Grab the current value of what was written to the Realtime Database. ...
Normalerweise werden Nutzer aufgefordert, Werte für Parameter anzugeben, wenn sie eine Erweiterung installieren. Wenn Sie den Emulator jedoch für Tests und die Entwicklung verwenden, überspringen Sie den Installationsprozess und geben stattdessen Werte für benutzerdefinierte Parameter mithilfe einer
env
-Datei an.Öffnen Sie
functions/integration-tests/extensions/rtdb-uppercase-messages.env
und ersetzen Sie dieGREETING
-Definition durch Folgendes:MESSAGE_PATH=/msgs/{pushId}/original
Der obige Pfad unterscheidet sich vom Standardpfad und vom Pfad, den Sie zuvor definiert haben. Dies dient nur dazu, zu prüfen, ob Ihre Definition wirksam wird, wenn Sie die aktualisierte Erweiterung ausprobieren.
Starten Sie jetzt den Emulator neu und rufen Sie noch einmal die Benutzeroberfläche des Datenbankemulators auf.
Bearbeiten Sie den Stammknoten der Datenbank mit dem oben definierten Pfad:
- Feld:
msgs
- Typ:
json
- Wert:
{"11": {"original": "recipe"}}
Wenn Sie Ihre Datenbankänderungen speichern, sollte die
makeuppercase
-Funktion der Erweiterung wie zuvor ausgelöst werden. Jetzt sollte sie aber auch den benutzerdefinierten Parameter in das Konsolenprotokoll ausgeben.- Feld:
7. Ereignis-Hooks für benutzerdefinierte Logik bereitstellen
Als Entwickler einer Erweiterung haben Sie bereits gesehen, wie ein Firebase-Produkt die von Ihrer Erweiterung bereitgestellte Logik auslösen kann: Das Erstellen neuer Einträge in der Realtime Database löst Ihre makeuppercase
-Funktion aus. Ihre Erweiterung kann eine ähnliche Beziehung zu den Nutzern haben, die sie installieren: Ihre Erweiterung kann eine vom Nutzer definierte Logik auslösen.
Eine Erweiterung kann synchrone Hooks, asynchrone Hooks oder beides bereitstellen. Mithilfe von synchronen Hooks können Nutzer Aufgaben ausführen, die den Abschluss einer Funktion der Erweiterung blockieren. Das kann beispielsweise nützlich sein, um Nutzern die Möglichkeit zu geben, eine benutzerdefinierte Vorverarbeitung durchzuführen, bevor eine Erweiterung ihre Arbeit beginnt.
In diesem Leitfaden fügen Sie Ihrer Erweiterung einen asynchronen Hook hinzu, mit dem Nutzer ihre eigenen Verarbeitungsschritte definieren können, die ausgeführt werden, nachdem Ihre Erweiterung die Nachricht in Großbuchstaben in die Realtime Database geschrieben hat. Bei asynchronen Hooks werden benutzerdefinierte Funktionen mit Eventarc ausgelöst. Erweiterungen deklarieren die Arten von Ereignissen, die sie senden. Wenn Nutzer die Erweiterung installieren, wählen sie die Ereignistypen aus, an denen sie interessiert sind. Wenn er mindestens ein Ereignis auswählt, stellt Firebase im Rahmen der Installation einen Eventarc-Kanal für die Erweiterung bereit. Nutzer können dann eigene Cloud-Funktionen bereitstellen, die auf diesem Kanal lauschen und ausgelöst werden, wenn die Erweiterung neue Ereignisse veröffentlicht.
So fügen Sie einen asynchronen Hook hinzu:
Fügen Sie in der Datei
extension.yaml
den folgenden Abschnitt hinzu, in dem der Ereignistyp deklariert wird, den die Erweiterung ausgibt:events: - type: test-publisher.rtdb-uppercase-messages.v1.complete description: >- Occurs when message uppercasing completes. The event subject will contain the RTDB URL of the uppercase message.
Ereignistypen müssen eindeutig sein. Verwenden Sie daher für Ereignisnamen immer das folgende Format:
<publisher-id>.<extension-id>.<version>.<description>
. Da du noch keine Publisher-ID hast, verwende vorersttest-publisher
.Fügen Sie am Ende der Funktion
makeuppercase
Code hinzu, der ein Ereignis des gerade deklarierten Typs veröffentlicht:functions/index.js
// Import the Eventarc library: import { initializeApp } from "firebase-admin/app"; import { getEventarc } from "firebase-admin/eventarc"; const app = initializeApp(); // In makeuppercase, after upperRef.set(uppercase), add: // Set eventChannel to a newly-initialized channel, or `undefined` if events // aren't enabled. const eventChannel = process.env.EVENTARC_CHANNEL && getEventarc().channel(process.env.EVENTARC_CHANNEL, { allowedEventTypes: process.env.EXT_SELECTED_EVENTS, }); // If events are enabled, publish a `complete` event to the configured // channel. eventChannel && eventChannel.publish({ type: "test-publisher.rtdb-uppercase-messages.v1.complete", subject: upperRef.toString(), data: { "original": original, "uppercase": uppercase, }, });
In diesem Beispielcode wird davon ausgegangen, dass die Umgebungsvariable
EVENTARC_CHANNEL
nur definiert ist, wenn der Nutzer mindestens einen Ereignistyp aktiviert hat. WennEVENTARC_CHANNEL
nicht definiert ist, wird im Code nicht versucht, Ereignisse zu veröffentlichen.Sie können einem Eventarc-Ereignis zusätzliche Informationen anhängen. Im obigen Beispiel enthält das Ereignis ein Feld
subject
mit einem Verweis auf den neu erstellten Wert und eine Nutzlastdata
mit der ursprünglichen Nachricht und der Nachricht in Großbuchstaben. Diese Informationen können von benutzerdefinierten Funktionen verwendet werden, die das Ereignis auslösen.Normalerweise werden die Umgebungsvariablen
EVENTARC_CHANNEL
undEXT_SELECTED_EVENTS
anhand der Optionen definiert, die der Nutzer bei der Installation ausgewählt hat. Definieren Sie für den Test mit dem Emulator diese Variablen manuell in der Dateirtdb-uppercase-messages.env
:EVENTARC_CHANNEL=locations/us-central1/channels/firebase EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
Sie haben jetzt alle Schritte ausgeführt, die zum Hinzufügen eines asynchronen Ereignis-Hooks zu Ihrer Erweiterung erforderlich sind.
Um diese neue Funktion auszuprobieren, die Sie gerade implementiert haben, übernehmen Sie in den nächsten Schritten die Rolle eines Nutzers, der die Erweiterung installiert:
Initialisieren Sie im Verzeichnis
functions/integration-tests
ein neues Firebase-Projekt:firebase init functions
Lehnen Sie die Einrichtung eines Standardprojekts ab, wählen Sie JavaScript als Cloud Functions-Sprache aus und installieren Sie die erforderlichen Abhängigkeiten. Dieses Projekt stellt das Projekt eines Nutzers dar, in dem Ihre Erweiterung installiert ist.
Bearbeiten Sie
integration-tests/functions/index.js
und fügen Sie den folgenden Code ein:import { logger } from "firebase-functions/v1"; import { onCustomEventPublished } from "firebase-functions/v2/eventarc"; import { initializeApp } from "firebase-admin/app"; import { getDatabase } from "firebase-admin/database"; const app = initializeApp(); export const extraemphasis = onCustomEventPublished( "test-publisher.rtdb-uppercase-messages.v1.complete", async (event) => { logger.info("Received makeuppercase completed event", event); const refUrl = event.subject; const ref = getDatabase().refFromURL(refUrl); const upper = (await ref.get()).val(); return ref.set(`${upper}!!!`); } );
Dies ist ein Beispiel für eine Funktion zur Nachbearbeitung, die ein Nutzer schreiben könnte. In diesem Fall überwacht die Funktion, ob die Erweiterung ein
complete
-Ereignis veröffentlicht. Wenn das der Fall ist, werden der Nachricht, die jetzt in Großbuchstaben geschrieben ist, drei Ausrufezeichen hinzugefügt.Starten Sie den Emulator neu. Der Emulator lädt die Funktionen der Erweiterung sowie die vom „Nutzer“ definierte Funktion zur Nachbearbeitung.
Rufen Sie die Benutzeroberfläche des Datenbankemulators auf und bearbeiten Sie den Stammknoten der Datenbank über den oben definierten Pfad:
- Feld:
msgs
- Typ:
json
- Wert:
{"11": {"original": "recipe"}}
Wenn Sie Ihre Datenbankänderungen speichern, sollten die
makeuppercase
-Funktion der Erweiterung und dieextraemphasis
-Funktion des Nutzers nacheinander ausgelöst werden, sodass das Feldupper
den WertRECIPE!!!
erhält.- Feld:
8. Lebenszyklusereignis-Handler hinzufügen
Die von Ihnen bisher geschriebene Erweiterung verarbeitet Nachrichten, sobald sie erstellt werden. Was ist aber, wenn Ihre Nutzer bereits eine Datenbank mit Nachrichten haben, wenn sie die Erweiterung installieren? Firebase Extensions bietet die Funktion Lifecycle-Ereignis-Hooks, mit der Sie Aktionen auslösen können, wenn Ihre Erweiterung installiert, aktualisiert oder neu konfiguriert wird. In diesem Abschnitt verwenden Sie Lebenszyklusereignis-Hooks, um die vorhandene Nachrichtendatenbank eines Projekts mit Großbuchstaben-Nachrichten zu füllen, wenn ein Nutzer Ihre Erweiterung installiert.
Firebase-Erweiterungen verwenden Cloud Tasks, um Ihre Lebenszyklusereignis-Handler auszuführen. Sie definieren Ereignis-Handler mit Cloud Functions. Wenn eine Instanz Ihrer Erweiterung eines der unterstützten Lebenszyklusereignisse erreicht und Sie einen Handler definiert haben, wird der Handler einer Cloud Tasks-Warteschlange hinzugefügt. Cloud Tasks führt den Handler dann asynchron aus. Während ein Lebenszyklusereignis-Handler ausgeführt wird, wird dem Nutzer in der Firebase Console angezeigt, dass für die Erweiterungs-Instanz ein Verarbeitungsvorgang läuft. Es liegt in der Verantwortung Ihrer Handlerfunktion, dem Nutzer den aktuellen Status und den Abschluss der Aufgabe zu melden.
So fügen Sie einen Lebenszyklus-Ereignis-Handler hinzu, der vorhandene Nachrichten nachträglich einfügt:
Definieren Sie eine neue Cloud Functions-Funktion, die durch Ereignisse in der Aufgabenwarteschlange ausgelöst wird:
functions/index.js
import { tasks } from "firebase-functions/v1"; import { getDatabase } from "firebase-admin/database"; import { getExtensions } from "firebase-admin/extensions"; import { getFunctions } from "firebase-admin/functions"; export const backfilldata = tasks.taskQueue().onDispatch(async () => { const batch = await getDatabase() .ref(process.env.MESSAGE_PATH) .parent.parent.orderByChild("upper") .limitToFirst(20) .get(); const promises = []; for (const key in batch.val()) { const msg = batch.child(key); if (msg.hasChild("original") && !msg.hasChild("upper")) { const upper = msg.child("original").val().toUpperCase(); promises.push(msg.child("upper").ref.set(upper)); } } await Promise.all(promises); if (promises.length > 0) { const queue = getFunctions().taskQueue( "backfilldata", process.env.EXT_INSTANCE_ID ); return queue.enqueue({}); } else { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill complete."); } });
Beachten Sie, dass die Funktion nur einige Einträge verarbeitet, bevor sie sich wieder der Aufgabenwarteschlange hinzufügt. Dies ist eine gängige Strategie, um mit Verarbeitungsaufgaben umzugehen, die nicht innerhalb des Zeitlimits einer Cloud-Funktion abgeschlossen werden können. Da Sie nicht vorhersagen können, wie viele Nachrichten ein Nutzer bereits in seiner Datenbank hat, wenn er Ihre Erweiterung installiert, ist diese Strategie gut geeignet.
Deklarieren Sie in der Datei
extension.yaml
die Backfill-Funktion als Erweiterungsressource mit dem AttributtaskQueueTrigger
:resources: - name: makeuppercase ... - name: backfilldata type: firebaseextensions.v1beta.function description: >- Backfill existing messages with uppercase versions properties: runtime: "nodejs18" taskQueueTrigger: {}
Deklarieren Sie dann die Funktion als Handler für das Lebenszyklusereignis
onInstall
:lifecycleEvents: onInstall: function: backfilldata processingMessage: Uppercasing existing messages
Das Backfilling vorhandener Nachrichten ist zwar praktisch, die Erweiterung funktioniert aber auch ohne. In solchen Fällen sollten Sie das Ausführen der Lebenszyklus-Ereignis-Handler optional machen.
Fügen Sie dazu
extension.yaml
einen neuen Parameter hinzu:- param: DO_BACKFILL label: Backfill existing messages description: >- Generate uppercase versions of existing messages? type: select required: true options: - label: Yes value: true - label: No value: false
Prüfen Sie dann zu Beginn der Backfill-Funktion den Wert des Parameters
DO_BACKFILL
und beenden Sie die Funktion, falls er nicht festgelegt ist:functions/index.js
if (!process.env.DO_BACKFILL) { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped."); }
Durch die oben genannten Änderungen werden vorhandene Nachrichten nach der Installation der Erweiterung in Großbuchstaben umgewandelt.
Bislang haben Sie den Erweiterungsemulator verwendet, um Ihre Erweiterung zu entwickeln und laufende Änderungen zu testen. Der Erweiterungsemulator überspringt jedoch den Installationsprozess. Wenn Sie Ihren onInstall
-Ereignishandler testen möchten, müssen Sie die Erweiterung in einem echten Projekt installieren. Das ist aber auch gut so, denn durch die zusätzliche Funktion für den automatischen Backfill ist die Anleitungserweiterung jetzt codefertig.
9. In einem echten Firebase-Projekt bereitstellen
Der Erweiterungsemulator ist ein hervorragendes Tool, um während der Entwicklung schnell Änderungen an einer Erweiterung vorzunehmen. Irgendwann sollten Sie sie jedoch in einem echten Projekt ausprobieren.
Richten Sie dazu zuerst ein neues Projekt mit einigen aktivierten Diensten ein:
- Fügen Sie in der Firebase Console ein neues Projekt hinzu.
- Führen Sie für Ihr Projekt ein Upgrade auf den Blaze-Tarif (Pay as you go) durch. Für Cloud Functions for Firebase ist ein Rechnungskonto für Ihr Projekt erforderlich. Sie benötigen also auch ein Rechnungskonto, um eine Erweiterung zu installieren.
- Aktivieren Sie in Ihrem neuen Projekt die Realtime Database.
- Da Sie die Fähigkeit Ihrer Erweiterung testen möchten, vorhandene Daten bei der Installation zu ergänzen, importieren Sie einige Beispieldaten in Ihre Echtzeit-Datenbankinstanz:
- Laden Sie einige RTDB-Startdaten herunter.
- Klicken Sie auf der Seite „Realtime Database“ (Realtime Database) der Firebase Console auf das Dreipunkt-Menü > „JSON importieren“ und wählen Sie die Datei aus, die Sie gerade heruntergeladen haben.
Wenn Sie die Backfill-Funktion für die
orderByChild
-Methode aktivieren möchten, konfigurieren Sie die Datenbank so, dass Nachrichten nach dem Wert vonupper
indexiert werden:{ "rules": { ".read": false, ".write": false, "messages": { ".indexOn": "upper" } } }
Installieren Sie nun die Erweiterung aus der lokalen Quelle im neuen Projekt:
Erstellen Sie ein neues Verzeichnis für Ihr Firebase-Projekt:
mkdir ~/extensions-live-test && cd ~/extensions-live-test
Initialisieren Sie ein Firebase-Projekt im Arbeitsverzeichnis:
firebase init database
Wählen Sie bei Aufforderung das Projekt aus, das Sie gerade erstellt haben.
Installieren Sie die Erweiterung in Ihrem lokalen Firebase-Projekt:
firebase ext:install /path/to/rtdb-uppercase-messages
Hier sehen Sie, wie die Installation einer Erweiterung mit der Firebase CLI abläuft. Wählen Sie „Ja“ aus, wenn Sie im Konfigurationstool gefragt werden, ob Sie Ihre vorhandene Datenbank auffüllen möchten.
Nachdem Sie die Konfigurationsoptionen ausgewählt haben, speichert die Firebase CLI Ihre Konfiguration im Verzeichnis
extensions
und zeichnet den Speicherort der Erweiterungsquelle in der Dateifirebase.json
auf. Zusammen werden diese beiden Einträge als Manifest für Erweiterungen bezeichnet. Nutzer können die Erweiterungskonfiguration mit dem Manifest speichern und in verschiedenen Projekten bereitstellen.Bereitstellung der Erweiterungskonfiguration in Ihrem Liveprojekt:
firebase deploy --only extensions
Wenn alles richtig funktioniert, sollte die Firebase CLI Ihre Erweiterung in Ihr Projekt hochladen und installieren. Nach Abschluss der Installation wird die Backfill-Aufgabe ausgeführt und innerhalb weniger Minuten wird Ihre Datenbank mit Großbuchstaben-Nachrichten aktualisiert. Fügen Sie der Nachrichtendatenbank einige neue Knoten hinzu und prüfen Sie, ob die Erweiterung auch für neue Nachrichten funktioniert.
10. Dokumentation schreiben
Bevor Sie Ihre Erweiterung für Nutzer freigeben, sollten Sie dafür sorgen, dass genügend Dokumentation vorhanden ist, damit sie erfolgreich eingesetzt werden kann.
Beim Initialisieren des Erweiterungsprojekts hat die Firebase CLI Stub-Versionen der Mindestdokumentation erstellt. Aktualisieren Sie diese Dateien, damit sie die von Ihnen erstellte Erweiterung korrekt widerspiegeln.
extension.yaml
Sie haben diese Datei bereits aktualisiert, während Sie diese Erweiterung entwickelt haben. Sie müssen sie also momentan nicht noch einmal aktualisieren.
Die in dieser Datei enthaltene Dokumentation ist jedoch sehr wichtig. Neben den wichtigen identifizierenden Informationen einer Erweiterung (Name, Beschreibung, Autor, offizieller Repository-Speicherort) enthält die extension.yaml
-Datei auch eine für Nutzer sichtbare Dokumentation für jede Ressource und jeden benutzerkonfigurierbaren Parameter. Diese Informationen werden Nutzern in der Firebase Console, im Extensions Hub und in der Firebase CLI angezeigt.
PREINSTALL.md
Geben Sie in dieser Datei Informationen an, die Nutzer benötigen, bevor sie Ihre Erweiterung installieren: Beschreiben Sie kurz, wozu die Erweiterung dient, erläutern Sie alle Voraussetzungen und informieren Sie die Nutzer über die Abrechnungsfolgen der Installation der Erweiterung. Wenn Sie eine Website mit zusätzlichen Informationen haben, ist dies auch ein guter Ort, um sie zu verlinken.
Der Text dieser Datei wird dem Nutzer im Extensions Hub und über den Befehl firebase ext:info
angezeigt.
Hier sehen Sie ein Beispiel für eine PREINSTALL-Datei:
Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.
This extension expects a database layout like the following example:
"messages": {
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
}
When you create new string records, this extension creates a new sibling record
with upper-cased text:
MESSAGE_ID: {
"original": MESSAGE_TEXT,
"upper": UPPERCASE_MESSAGE_TEXT,
}
#### Additional setup
Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.
#### Billing
To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).
- This extension uses other Firebase and Google Cloud Platform services, which
have associated charges if you exceed the service's no-cost tier:
- Realtime Database
- Cloud Functions (Node.js 10+ runtime)
[See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
[Eventarc fees apply](https://cloud.google.com/eventarc/pricing).
POSTINSTALL.md
Diese Datei enthält Informationen, die für Nutzer nützlich sind, nachdem sie Ihre Erweiterung installiert haben. Dazu gehören beispielsweise weitere Einrichtungsschritte und ein Beispiel für die Verwendung der Erweiterung.
Der Inhalt von POSTINSTALL.md wird in der Firebase Console angezeigt, nachdem eine Erweiterung konfiguriert und installiert wurde. Sie können in dieser Datei auf Nutzerparameter verweisen. Sie werden dann durch die konfigurierten Werte ersetzt.
Hier ist eine Beispieldatei für die Erweiterung nach der Installation:
### See it in action
You can test out this extension right away!
1. Go to your
[Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.
1. Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.
1. In a few seconds, you'll see a sibling node named `upper` that contains the
message in upper case.
### Using the extension
We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).
### Monitoring
As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.
CHANGELOG.md
Außerdem sollten Sie die Änderungen, die Sie zwischen den Releases einer Erweiterung vornehmen, in der Datei CHANGELOG.md
dokumentieren.
Da die Beispielerweiterung noch nie veröffentlicht wurde, enthält das Änderungsprotokoll nur einen Eintrag:
## Version 0.0.1
Initial release of the _Convert messages to upper case_ extension.
README.md
Die meisten Erweiterungen enthalten auch eine Readme-Datei für Nutzer, die das Repository der Erweiterung besuchen. Sie können diese Datei manuell schreiben oder mit dem Befehl eine Readme-Datei generieren.
Überspringen Sie für diesen Leitfaden das Erstellen einer readme-Datei.
Zusätzliche Dokumentation
Die oben beschriebene Dokumentation ist die Mindestdokumentation, die Sie Nutzern zur Verfügung stellen sollten. Viele Erweiterungen erfordern eine detailliertere Dokumentation, damit Nutzer sie erfolgreich verwenden können. In diesem Fall sollten Sie zusätzliche Dokumentationen erstellen und an einem Ort hosten, auf den Sie Nutzer verweisen können.
Für die Zwecke dieses Leitfadens wird das Erstellen einer umfangreicheren Dokumentation übersprungen.
11. Im Erweiterungs-Hub veröffentlichen
Jetzt, da der Code Ihrer Erweiterung vollständig ist und sie dokumentiert wurde, können Sie sie im Erweiterungs-Hub veröffentlichen. Da es sich aber nur um eine Demo handelt, sollten Sie das nicht tun. Schreiben Sie jetzt Ihre eigene Erweiterung. Nutzen Sie dabei die Informationen in diesem Artikel und in der restlichen Firebase Extensions Publisher-Dokumentation und sehen Sie sich die Quelle der offiziellen, von Firebase erstellten Erweiterungen an.
So veröffentlichen Sie Ihre Arbeit im Erweiterungs-Hub:
- Wenn Sie Ihre erste Erweiterung veröffentlichen, registrieren Sie sich als Erweiterungsanbieter. Wenn Sie sich als Publisher von Erweiterungen registrieren, erstellen Sie eine Publisher-ID, anhand derer Nutzer Sie schnell als Autor Ihrer Erweiterungen identifizieren können.
Hosten Sie den Quellcode Ihrer Erweiterung an einem öffentlich verifizierbaren Speicherort. Wenn Ihr Code aus einer überprüfbaren Quelle verfügbar ist, kann Firebase Ihre Erweiterung direkt an diesem Speicherort veröffentlichen. So können Sie sicherstellen, dass Sie die aktuell veröffentlichte Version Ihrer Erweiterung veröffentlichen. Außerdem können Nutzer den Code prüfen, den sie in ihren Projekten installieren.
Derzeit bedeutet das, dass Sie Ihre Erweiterung in einem öffentlichen GitHub-Repository verfügbar machen müssen.
Laden Sie Ihre Erweiterung mit dem Befehl
firebase ext:dev:upload
in den Erweiterungs-Hub hoch.Rufen Sie in der Firebase Console Ihr Publisher-Dashboard auf, suchen Sie die gerade hochgeladene Erweiterung und klicken Sie auf „Im Erweiterungs-Hub veröffentlichen“. Dies löst eine Überprüfung durch unser Team aus, die einige Tage dauern kann. Wenn die Erweiterung genehmigt wird, wird sie im Erweiterungs-Hub veröffentlicht. Wenn Ihr Antrag abgelehnt wird, erhalten Sie eine Nachricht mit einer Begründung. Sie können dann die gemeldeten Probleme beheben und den Antrag noch einmal zur Überprüfung einreichen.