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 ausprobieren
Als die Firebase CLI das neue Erweiterungsverzeichnis initialisiert hat, wurden eine einfache Beispielfunktion und ein integration-tests
-Verzeichnis mit den Dateien erstellt, die zum Ausführen einer Erweiterung mithilfe 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
). Die Erweiterung besteht bisher aus einer einzelnen HTTP-ausgelösten Funktion,greetTheWorld
, die beim Zugriff eine "Hello World"-Nachricht 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); });
Während der Emulator ausgeführt wird, werden alle Änderungen, die Sie am 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.
In einem einfachen ersten Schritt können Sie die vordefinierten Erweiterungsmetadaten so bearbeiten, dass sie die zu schreibende Erweiterung anstelle von 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 im Feld
name
verwendete Namenskonvention: Offizielle Firebase-Erweiterungen werden mit einem Präfix benannt, das das primäre Firebase-Produkt angibt, für das die Erweiterung ausgeführt 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 Functions-Funktion schreiben und als Erweiterungsressource deklarieren
Jetzt können Sie mit dem Schreiben von Code beginnen. In diesem Schritt schreiben Sie eine Cloud Functions-Funktion, die die Hauptaufgabe Ihrer Erweiterung ausführt: Ihre Realtime Database auf Nachrichten überwacht und sie in Großbuchstaben 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 durch HTTP ausgelöste Funktion, die beim Zugriff auf einen HTTP-Endpunkt ausgeführt wurde. Die neue Funktion wird durch Datenbankereignisse in Echtzeit ausgelöst: Sie sucht in einem bestimmten Pfad nach neuen Elementen und schreibt, sobald ein solches erkannt wird, die Version des Werts in Großbuchstaben zurück in die Datenbank.
Übrigens verwendet diese neue Datei die ECMAScript-Modulsyntax (
import
undexport
) anstelle von CommonJS (require
). 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 der 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 durch Drücken von 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 Ihre aktualisierte Erweiterung:
Öffnen Sie die Benutzeroberfläche des Datenbankemulators über den Link, den der Emulator beim Start 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. Jedes Mal, wenn Sie einen neuen Eintrag hinzufügen, sollte die Erweiterung das Felduppercase
hinzufügen, das den Inhalt des Feldsoriginal
in Großbuchstaben enthält.
Sie haben jetzt eine vollständige, aber einfache Erweiterung, die auf einer RTDB-Instanz ausgeführt wird. In den folgenden Abschnitten werden diese Erweiterung durch einige zusätzliche Funktionen optimiert. 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 eingeschränkten Zugriff auf das Projekt und die zugehörigen Daten. Dazu wird ein instanzspezifisches Dienstkonto verwendet. 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. Auf diese Weise können Nutzer Ihre Erweiterung für ihre vorhandene Datenbankeinrichtung 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
Beachten Sie, dass diese Änderung in Firebase Extensions ausschließlich der Dokumentation dient: Wenn eine Cloud Functions-Funktion als Teil einer Erweiterung bereitgestellt wird, verwendet sie die Triggerdefinition aus der Datei
extension.yaml
und ignoriert den in der Funktionsdefinition angegebenen Wert. Es empfiehlt sich jedoch, in Ihrem Code zu dokumentieren, woher dieser Wert stammt.Es kann enttäuschend sein, eine Codeänderung ohne Laufzeitauswirkung vorzunehmen. Wichtig ist jedoch, dass Sie auf jeden benutzerdefinierten Parameter in Ihrem Funktionscode 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 bei der Installation einer Erweiterung aufgefordert, Werte für Parameter anzugeben. 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 über Eventarc ausgelöst. Erweiterungen deklarieren die Ereignistypen, die sie ausgeben, und 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.
Führen Sie die folgenden Schritte aus, um einen asynchronen Hook hinzuzufügen:
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>
. (Sie haben noch keine Publisher-ID, verwenden Sie daher vorerst nurtest-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 diese Variablen zum Testen mit dem Emulator 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.
Übernimm in den nächsten Schritten die Rolle eines Nutzers, der die Erweiterung installiert, um diese neue Funktion auszuprobieren:
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. Aber was ist, wenn Ihre Nutzer bei der Installation der Erweiterung bereits eine Nachrichtendatenbank haben? 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 Extensions verwendet Cloud Tasks, um Ihre Lebenszyklus-Event-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. Die Handler-Funktion muss den aktuellen Status und die Aufgabenerledigung an den Nutzer zurückmelden.
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 häufig verwendete Strategie für Verarbeitungsaufgaben, die nicht innerhalb des Zeitlimits einer Cloud Functions-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, eignet sich diese Strategie gut.
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 einen neuen Parameter zu
extension.yaml
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."); }
Mit den oben genannten Änderungen konvertiert die Erweiterung bei der Installation vorhandene Nachrichten in Großbuchstaben.
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. Genauso gut, da die Erweiterung der Anleitung jetzt mit dem automatischen Backfill den Code vollständig umfasst.
9. In echtem 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 ein Upgrade Ihres Projekts auf den Blaze-Tarif mit Abrechnung nach Verbrauch durch. Für Cloud Functions for Firebase muss Ihr Projekt ein Rechnungskonto haben. 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 Datensätze als Erweiterungsmanifest bezeichnet. Nutzer können die Erweiterungskonfiguration mit dem Manifest speichern und in verschiedenen Projekten bereitstellen.Stellen Sie die Erweiterungskonfiguration für Ihr Live-Projekt bereit:
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.
Bei der Initialisierung des Erweiterungsprojekts hat die Firebase CLI Stub-Versionen der erforderlichen Mindestdokumentation erstellt. Aktualisieren Sie diese Dateien, damit sie die von Ihnen erstellte Erweiterung korrekt widerspiegeln.
extension.yaml
Sie haben diese Datei bereits mit der Entwicklung dieser Erweiterung aktualisiert, daher müssen Sie im Moment keine weiteren Aktualisierungen vornehmen.
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 mit dem 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 bieten auch eine Readme-Datei für Nutzer, die das Repository der Erweiterung besuchen. Sie können diese Datei von Hand schreiben oder mit dem Befehl eine Readme-Datei generieren.
Für die Zwecke dieses Leitfadens überspringen Sie das Schreiben 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 Dokumentation schreiben und an einem Ort hosten, auf den Nutzer verweisen können.
Für die Zwecke dieses Leitfadens überspringen Sie das Schreiben einer ausführlicheren Dokumentation.
11. Im Erweiterungs-Hub veröffentlichen
Nachdem der Code Ihrer Erweiterung nun vollständig und dokumentiert ist, können Sie sie im Erweiterungs-Hub freigeben. Da dies aber nur eine Demo ist, 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 die Erweiterung mit dem Befehl
firebase ext:dev:upload
in Erweiterungs-Hub hoch.Rufe dein Publisher-Dashboard in der Firebase Console auf, suche nach der gerade hochgeladenen Erweiterung und klicke auf „Im Extensions 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 der 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.