Rozpocznij tworzenie rozszerzenia

Ta strona przeprowadzi Cię przez kroki wymagane do zbudowania prostego rozszerzenia Firebase, które możesz zainstalować w swoich projektach lub udostępnić innym. Ten prosty przykład rozszerzenia Firebase będzie przeglądał bazę danych czasu rzeczywistego pod kątem wiadomości i konwertował je na wielkie litery.

1. Skonfiguruj środowisko i zainicjuj projekt

Zanim zaczniesz tworzyć rozszerzenie, musisz skonfigurować środowisko kompilacji z wymaganymi narzędziami.

  1. Zainstaluj Node.js 16 lub nowszy. Jednym ze sposobów zainstalowania Node jest użycie nvm (lub nvm-windows ).

  2. Zainstaluj lub zaktualizuj do najnowszej wersji Firebase CLI . Aby zainstalować lub zaktualizować za pomocą npm , uruchom to polecenie:

    npm install -g firebase-tools
    

Teraz użyj interfejsu CLI Firebase, aby zainicjować nowy projekt rozszerzenia:

  1. Utwórz katalog dla swojego rozszerzenia i włóż do niego cd :

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
    
  2. Uruchom polecenie ext:dev:init interfejsu Firebase CLI:

    firebase ext:dev:init
    

    Gdy pojawi się monit, wybierz JavaScript jako język funkcji (pamiętaj jednak, że możesz także używać TypeScriptu, gdy tworzysz własne rozszerzenie), a gdy zostaniesz poproszony o zainstalowanie zależności, odpowiedz „tak”. (Zaakceptuj wartości domyślne pozostałych opcji.) To polecenie skonfiguruje szkieletową bazę kodu dla nowego rozszerzenia, od której będziesz mógł rozpocząć tworzenie swojego rozszerzenia.

2. Wypróbuj przykładowe rozszerzenie za pomocą emulatora

Kiedy interfejs CLI Firebase zainicjował nowy katalog rozszerzeń, utworzył prostą przykładową funkcję i katalog integration-tests , który zawiera pliki niezbędne do uruchomienia rozszerzenia przy użyciu zestawu emulatorów Firebase.

Spróbuj uruchomić przykładowe rozszerzenie w emulatorze:

  1. Przejdź do katalogu integration-tests :

    cd functions/integration-tests
    
  2. Uruchom emulator z projektem demonstracyjnym:

    firebase emulators:start --project=demo-test
    

    Emulator ładuje rozszerzenie do predefiniowanego „fikcyjnego” projektu ( demo-test ). Dotychczasowe rozszerzenie składa się z pojedynczej funkcji uruchamianej przez HTTP, greetTheWorld , która po uzyskaniu dostępu zwraca komunikat „witaj świecie”.

  3. Gdy emulator jest nadal uruchomiony, wypróbuj funkcję greetTheWorld rozszerzenia, odwiedzając adres URL wyświetlony podczas jego uruchamiania.

    Twoja przeglądarka wyświetla komunikat „Hello World, witaj na świecie”.

  4. Kod źródłowy tej funkcji znajduje się w katalogu functions rozszerzenia. Otwórz źródło w wybranym edytorze lub IDE:

    funkcje/indeks.js

    const functions = require("firebase-functions");
    
    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);
    });
    
  5. Gdy emulator jest uruchomiony, automatycznie przeładuje wszelkie zmiany wprowadzone w kodzie funkcji. Spróbuj wprowadzić małą zmianę w funkcji greetTheWorld :

    funkcje/indeks.js

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    Zapisz zmiany. Emulator przeładuje Twój kod i teraz, gdy odwiedzisz adres URL funkcji, zobaczysz zaktualizowane powitanie.

3. Dodaj podstawowe informacje do pliku Extension.yaml

Teraz, gdy masz już skonfigurowane środowisko programistyczne i uruchomiłeś emulator rozszerzeń, możesz zacząć pisać własne rozszerzenie.

Jako skromny pierwszy krok zmodyfikuj wstępnie zdefiniowane metadane rozszerzenia, aby odzwierciedlały rozszerzenie, które chcesz napisać, a nie greet-the-world . Te metadane są przechowywane w pliku extension.yaml .

  1. Otwórz extension.yaml w swoim edytorze i zamień całą zawartość pliku na następującą:

    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
    

    Zwróć uwagę na konwencję nazewnictwa zastosowaną w polu name : oficjalne rozszerzenia Firebase mają przedrostek wskazujący podstawowy produkt Firebase, na którym działa dane rozszerzenie, po którym następuje opis działania rozszerzenia. Powinieneś używać tej samej konwencji we własnych rozszerzeniach.

  2. Ponieważ zmieniłeś nazwę swojego rozszerzenia, powinieneś także zaktualizować konfigurację emulatora o nową nazwę:

    1. functions/integration-tests/firebase.json zmień greet-the-world na rtdb-uppercase-messages .
    2. Zmień nazwę functions/integration-tests/extensions/greet-the-world.env na functions/integration-tests/extensions/rtdb-uppercase-messages.env .

W kodzie rozszerzenia nadal znajdują się pozostałości rozszerzenia greet-the-world , ale zostaw je na razie. Zaktualizujesz je w kilku następnych sekcjach.

4. Napisz funkcję chmury i zadeklaruj ją jako zasób rozszerzenia

Teraz możesz zacząć pisać kod. Na tym etapie napiszesz funkcję chmury, która wykona podstawowe zadanie Twojego rozszerzenia, czyli przeglądanie bazy danych w czasie rzeczywistym pod kątem wiadomości i konwertowanie ich na wielkie litery.

  1. Otwórz źródło funkcji rozszerzenia (w katalogu functions rozszerzenia) w wybranym edytorze lub środowisku IDE. Zastąp jego zawartość następującą treścią:

    funkcje/indeks.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);
    });
    

    Stara funkcja, którą zastąpiłeś, była funkcją wyzwalaną przez protokół HTTP i działała po uzyskaniu dostępu do punktu końcowego HTTP. Nowa funkcja jest uruchamiana na podstawie zdarzeń w bazie danych w czasie rzeczywistym: wyszukuje nowe elementy na określonej ścieżce i w przypadku ich wykrycia zapisuje wartość z powrotem do bazy danych.

    Nawiasem mówiąc, ten nowy plik używa składni modułu ECMAScript ( import i export ) zamiast CommonJS ( require ). Aby używać modułów ES w węźle, określ "type": "module" functions/package.json :

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      …
    }
    
  2. Każda funkcja w Twoim rozszerzeniu musi być zadeklarowana w pliku extension.yaml . Przykładowe rozszerzenie zadeklarowało greetTheWorld jako jedyną funkcję w chmurze rozszerzenia; teraz, gdy zastąpiłeś go makeuppercase , musisz także zaktualizować jego deklarację.

    Otwórz extension.yaml i dodaj pole resources :

    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"
    
  3. Ponieważ Twoje rozszerzenie używa teraz bazy danych czasu rzeczywistego jako wyzwalacza, musisz zaktualizować konfigurację emulatora, aby uruchomić emulator RTDB razem z emulatorem Cloud Functions:

    1. Jeśli emulator nadal działa, zatrzymaj go, naciskając Ctrl-C.

    2. Z katalogufunctions functions/integration-tests uruchom następującą komendę:

      firebase init emulators
      

      Gdy zostaniesz o to poproszony, pomiń konfigurowanie projektu domyślnego, a następnie wybierz emulatory funkcji i bazy danych. Zaakceptuj domyślne porty i pozwól narzędziu instalacyjnemu pobrać wymagane pliki.

    3. Uruchom ponownie emulator:

      firebase emulators:start --project=demo-test
      
  4. Wypróbuj zaktualizowane rozszerzenie:

    1. Otwórz interfejs emulatora bazy danych, korzystając z łącza wydrukowanego podczas uruchamiania emulatora.

    2. Edytuj węzeł główny bazy danych:

      • Pole: messages
      • Typ: json
      • Wartość: {"11": {"original": "recipe"}}

      Jeśli wszystko jest skonfigurowane poprawnie, po zapisaniu zmian w bazie danych funkcja makeuppercase rozszerzenia powinna uruchomić się i dodać rekord podrzędny do wiadomości 11 o treści "upper": "RECIPE" . Przyjrzyj się dziennikom i zakładkom bazy danych interfejsu użytkownika emulatora, aby potwierdzić oczekiwane wyniki.

    3. Spróbuj dodać więcej elementów podrzędnych do węzła messages ( {"original":"any text"} ). Za każdym razem, gdy dodajesz nowy rekord, rozszerzenie powinno dodać pole zawierające uppercase zawierające wielką zawartość original pola.

Masz teraz kompletne, choć proste rozszerzenie, które działa na instancji RTDB. W kolejnych sekcjach udoskonalisz to rozszerzenie, dodając kilka dodatkowych funkcji. Następnie przygotujesz rozszerzenie do dystrybucji wśród innych, a na koniec dowiesz się, jak opublikować swoje rozszerzenie w Centrum rozszerzeń.

5. Zadeklaruj interfejsy API i role

Firebase przyznaje każdej instancji zainstalowanego rozszerzenia ograniczony dostęp do projektu i jego danych za pomocą konta usługi dla poszczególnych instancji. Każde konto posiada minimalny zestaw uprawnień potrzebnych do działania. Z tego powodu musisz wyraźnie zadeklarować wszelkie role IAM wymagane przez Twoje rozszerzenie; gdy użytkownicy instalują Twoje rozszerzenie, Firebase tworzy konto usługi z przyznanymi tymi rolami i używa go do uruchamiania rozszerzenia.

Nie musisz deklarować ról, aby wywołać zdarzenia związane z produktem, ale musisz zadeklarować rolę, aby w inny sposób z nią wchodzić w interakcję. Ponieważ funkcja dodana w ostatnim kroku zapisuje dane do bazy danych Realtime Database, musisz dodać następującą deklarację do extension.yaml :

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

Podobnie deklarujesz interfejsy API Google, których używa rozszerzenie, w polu apis . Gdy użytkownicy zainstalują Twoje rozszerzenie, zostaną zapytani, czy chcą automatycznie włączyć te interfejsy API w swoim projekcie. Jest to zazwyczaj konieczne tylko w przypadku interfejsów API Google innych niż Firebase i nie jest potrzebne w tym przewodniku.

6. Zdefiniuj parametry konfigurowane przez użytkownika

Funkcja utworzona w dwóch ostatnich krokach obserwowała określoną lokalizację RTDB pod kątem przychodzących wiadomości. Czasami naprawdę chcesz oglądać konkretną lokalizację, na przykład gdy Twoje rozszerzenie działa w oparciu o strukturę bazy danych, której używasz wyłącznie dla swojego rozszerzenia. Jednak w większości przypadków będziesz chciał, aby te wartości mogły być konfigurowane przez użytkowników, którzy instalują Twoje rozszerzenie w swoich projektach. W ten sposób użytkownicy będą mogli wykorzystać Twoje rozszerzenie do pracy z istniejącą konfiguracją bazy danych.

Ustaw ścieżkę, którą rozszerzenie obserwuje pod kątem nowych wiadomości, aby użytkownik mógł ją konfigurować:

  1. W pliku extension.yaml dodaj sekcję params :

    - 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
    

    Definiuje to nowy parametr w postaci ciągu znaków, o ustawienie którego użytkownicy będą proszeni podczas instalowania rozszerzenia.

  2. Będąc nadal w pliku extension.yaml , wróć do deklaracji makeuppercase i zmień pole resource na następujące:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    Token ${param:MESSAGE_PATH} jest odniesieniem do właśnie zdefiniowanego parametru. Po uruchomieniu rozszerzenia ten token zostanie zastąpiony dowolną wartością skonfigurowaną przez użytkownika dla tego parametru, w wyniku czego funkcja makeuppercase będzie nasłuchiwać ścieżki określonej przez użytkownika. Możesz użyć tej składni, aby odwołać się do dowolnego parametru zdefiniowanego przez użytkownika w dowolnym miejscu extension.yaml (oraz POSTINSTALL.md — więcej o tym później).

  3. Dostęp do parametrów zdefiniowanych przez użytkownika można także uzyskać z poziomu kodu funkcji.

    W funkcji, którą napisałeś w ostatniej sekcji, zakodowałeś na stałe ścieżkę, aby obserwować zmiany. Zmień definicję wyzwalacza, aby zamiast tego odwoływała się do wartości zdefiniowanej przez użytkownika:

    funkcje/indeks.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    Należy pamiętać, że w rozszerzeniach Firebase ta zmiana ma wyłącznie charakter dokumentacyjny: gdy funkcja chmury jest wdrażana jako część rozszerzenia, korzysta ona z definicji wyzwalacza z pliku extension.yaml i ignoruje wartość określoną w definicji funkcji. Niemniej jednak dobrym pomysłem jest udokumentowanie w kodzie, skąd pochodzi ta wartość.

  4. Zmiana kodu, która nie ma wpływu na środowisko wykonawcze, może wydawać się rozczarowująca, ale ważną lekcją, jaką należy wyciągnąć, jest to, że możesz uzyskać dostęp do dowolnego parametru zdefiniowanego przez użytkownika w kodzie funkcji i użyć go jako zwykłej wartości w logice funkcji. Jako ukłon w stronę tej możliwości dodaj następującą instrukcję dziennika, aby wykazać, że rzeczywiście uzyskujesz dostęp do wartości zdefiniowanej przez użytkownika:

    funkcje/indeks.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.
        ...
    
  5. Zwykle podczas instalowania rozszerzenia użytkownicy są proszeni o podanie wartości parametrów. Kiedy jednak używasz emulatora do testowania i programowania, pomijasz proces instalacji, więc zamiast tego podajesz wartości parametrów zdefiniowanych przez użytkownika za pomocą pliku env .

    Otwórz functions/integration-tests/extensions/rtdb-uppercase-messages.env i zamień definicję GREETING na następującą:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Zauważ, że powyższa ścieżka różni się od ścieżki domyślnej i ścieżki, którą wcześniej zdefiniowałeś; ma to na celu tylko udowodnienie sobie, gdy wypróbujesz zaktualizowane rozszerzenie, że Twoja definicja zaczyna obowiązywać.

  6. Teraz uruchom ponownie emulator i jeszcze raz odwiedź interfejs emulatora bazy danych.

    Edytuj węzeł główny bazy danych, korzystając ze ścieżki zdefiniowanej powyżej:

    • Pole: msgs
    • Typ: json
    • Wartość: {"11": {"original": "recipe"}}

    Po zapisaniu zmian w bazie danych funkcja makeuppercase rozszerzenia powinna zostać uruchomiona tak jak wcześniej, ale teraz powinna również wydrukować parametr zdefiniowany przez użytkownika w dzienniku konsoli.

7. Zapewnij zaczepy zdarzeń dla logiki zdefiniowanej przez użytkownika

Jako autor rozszerzenia widziałeś już, jak produkt Firebase może uruchomić logikę dostarczoną przez rozszerzenie: utworzenie nowych rekordów w bazie danych Realtime uruchamia funkcję makeuppercase . Twoje rozszerzenie może mieć analogiczną relację z użytkownikami, którzy je instalują: Twoje rozszerzenie może uruchamiać logikę zdefiniowaną przez użytkownika .

Rozszerzenie może udostępniać haki synchroniczne , asynchroniczne lub oba. Synchroniczne zaczepy umożliwiają użytkownikom wykonywanie zadań blokujących wykonanie jednej z funkcji rozszerzenia. Może to być przydatne, na przykład, aby dać użytkownikom możliwość przeprowadzenia niestandardowego przetwarzania wstępnego, zanim rozszerzenie zacznie działać.

W tym przewodniku dodasz do rozszerzenia asynchroniczny element przechwytujący, który umożliwi użytkownikom zdefiniowanie własnych kroków przetwarzania, które będą uruchamiane po zapisaniu przez rozszerzenie komunikatu zawierającego wielkie litery w bazie danych czasu rzeczywistego. Asynchroniczne zaczepy wykorzystują Eventarc do wyzwalania funkcji zdefiniowanych przez użytkownika. Rozszerzenia deklarują typy emitowanych przez siebie zdarzeń, a gdy użytkownicy instalują rozszerzenie, wybierają typy zdarzeń, które ich interesują. Jeśli wybiorą co najmniej jedno zdarzenie, Firebase udostępni kanał Eventarc dla rozszerzenia w ramach procesu instalacji . Użytkownicy mogą następnie wdrożyć własne funkcje w chmurze, które nasłuchują na tym kanale i uruchamiają się, gdy rozszerzenie opublikuje nowe zdarzenia.

Wykonaj poniższe kroki, aby dodać asynchroniczny hak:

  1. W pliku extension.yaml dodaj następującą sekcję, która deklaruje jeden typ zdarzenia emitowanego przez rozszerzenie:

    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.
    

    Typy zdarzeń muszą być uniwersalnie unikalne; aby zapewnić niepowtarzalność, zawsze nazywaj swoje wydarzenia w następującym formacie: <publisher-id>.<extension-id>.<version>.<description> . (Nie masz jeszcze identyfikatora wydawcy, więc na razie użyj test-publisher .)

  2. Na koniec funkcji makeuppercase dodaj kod, który opublikuje zdarzenie zadeklarowanego typu:

    funkcje/indeks.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,
        },
      });
    

    W tym przykładowym kodzie wykorzystano fakt, że zmienna środowiskowa EVENTARC_CHANNEL jest zdefiniowana tylko wtedy, gdy użytkownik włączył co najmniej jeden typ zdarzenia. jeśli EVENTARC_CHANNEL nie jest zdefiniowany, kod nie próbuje publikować żadnych zdarzeń.

    Możesz dołączyć dodatkowe informacje do wydarzenia Eventarc. W powyższym przykładzie zdarzenie ma pole subject zawierające odniesienie do nowo utworzonej wartości oraz ładunek data zawierający komunikat oryginalny i pisany wielkimi literami. Zdefiniowane przez użytkownika funkcje wyzwalające zdarzenie mogą wykorzystywać te informacje.

  3. Zwykle zmienne środowiskowe EVENTARC_CHANNEL i EXT_SELECTED_EVENTS są definiowane na podstawie opcji wybranych przez użytkownika podczas instalacji. Aby przetestować emulator, zdefiniuj ręcznie te zmienne w pliku rtdb-uppercase-messages.env :

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

W tym momencie ukończyłeś kroki niezbędne do dodania asynchronicznego haka zdarzenia do swojego rozszerzenia.

Aby wypróbować tę nową, właśnie zaimplementowaną funkcję, w kilku kolejnych krokach wciel się w rolę użytkownika instalującego rozszerzenie:

  1. Z katalogufunctions functions/integration-tests zainicjuj nowy projekt Firebase:

    firebase init functions
    

    Po wyświetleniu monitu odmów skonfigurowania projektu domyślnego, wybierz JavaScript jako język Cloud Functions i zainstaluj wymagane zależności. Ten projekt reprezentuje projekt użytkownika , w którym zainstalowane jest Twoje rozszerzenie.

  2. Edytuj integration-tests/functions/index.js i wklej następujący kod:

    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}!!!`);
      }
    );
    

    To jest przykład funkcji przetwarzania końcowego, którą może napisać użytkownik. W tym przypadku funkcja nasłuchuje, czy rozszerzenie opublikuje complete zdarzenie, a po uruchomieniu dodaje trzy wykrzykniki do wiadomości pisanej wielkimi literami.

  3. Uruchom ponownie emulator. Emulator załaduje funkcje rozszerzenia, a także funkcję przetwarzania końcowego zdefiniowaną przez „użytkownika”.

  4. Odwiedź interfejs emulatora bazy danych i edytuj węzeł główny bazy danych, korzystając ze ścieżki zdefiniowanej powyżej:

    • Pole: msgs
    • Typ: json
    • Wartość: {"11": {"original": "recipe"}}

    Kiedy zapiszesz zmiany w bazie danych, funkcja makeuppercase i funkcja extraemphasis użytkownika powinny wywołać się po kolei, w wyniku czego w upper polu zostanie wyświetlona wartość RECIPE!!! .

8. Dodaj procedury obsługi zdarzeń cyklu życia

Rozszerzenie, które do tej pory napisałeś, przetwarza wiadomości w momencie ich tworzenia. Ale co, jeśli Twoi użytkownicy mają już bazę danych wiadomości, gdy instalują rozszerzenie? Rozszerzenia Firebase mają funkcję zwaną hakami zdarzeń cyklu życia , których możesz użyć do wyzwalania działań po zainstalowaniu, aktualizacji lub ponownej konfiguracji rozszerzenia. W tej sekcji użyjesz haków zdarzeń cyklu życia, aby wypełnić istniejącą bazę danych komunikatów projektu komunikatami pisanymi wielkimi literami, gdy użytkownik zainstaluje Twoje rozszerzenie.

Rozszerzenia Firebase korzystają z zadań w chmurze do uruchamiania programów obsługi zdarzeń cyklu życia. Definiujesz procedury obsługi zdarzeń za pomocą Cloud Functions; za każdym razem, gdy instancja Twojego rozszerzenia osiągnie jedno z obsługiwanych zdarzeń cyklu życia, jeśli zdefiniowałeś procedurę obsługi, zostanie ona dodana do kolejki Cloud Tasks. Cloud Tasks następnie asynchronicznie wykona procedurę obsługi. Gdy działa procedura obsługi zdarzeń cyklu życia, konsola Firebase zgłosi użytkownikowi, że w instancji rozszerzenia trwa zadanie przetwarzania. Do funkcji obsługi należy raportowanie użytkownikowi bieżącego stanu i zakończenia zadania.

Aby dodać procedurę obsługi zdarzeń cyklu życia, która uzupełnia istniejące komunikaty, wykonaj następujące czynności:

  1. Zdefiniuj nową funkcję Cloud, która będzie wyzwalana przez zdarzenia w kolejce zadań:

    funkcje/indeks.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.");
      }
    });
    

    Zwróć uwagę, że funkcja przetwarza tylko kilka rekordów, zanim ponownie doda się do kolejki zadań. Jest to powszechnie stosowana strategia radzenia sobie z zadaniami przetwarzania, których nie można ukończyć w oknie limitu czasu Funkcji Cloud. Ponieważ nie możesz przewidzieć, ile wiadomości użytkownik może już mieć w swojej bazie danych po zainstalowaniu Twojego rozszerzenia, ta strategia jest dobrym rozwiązaniem.

  2. W pliku extension.yaml zadeklaruj funkcję wypełniania jako zasób rozszerzenia posiadający właściwość taskQueueTrigger :

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    Następnie zadeklaruj funkcję jako procedurę obsługi zdarzenia cyklu życia onInstall :

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. Chociaż uzupełnianie istniejących wiadomości jest fajne, rozszerzenie może nadal działać bez niego. W takich sytuacjach należy uczynić uruchamianie procedur obsługi zdarzeń cyklu życia opcjonalnym.

    Aby to zrobić, dodaj nowy parametr do extension.yaml :

    - 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
    

    Następnie na początku funkcji wypełniania sprawdź wartość parametru DO_BACKFILL i wyjdź wcześniej, jeśli nie jest ustawiony:

    funkcje/indeks.js

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

Dzięki powyższym zmianom rozszerzenie po zainstalowaniu będzie teraz konwertować istniejące wiadomości na wielkie litery.

Do tego momentu używałeś emulatora rozszerzenia do rozwijania rozszerzenia i testowania bieżących zmian. Jednak emulator rozszerzenia pomija proces instalacji, więc aby przetestować procedurę obsługi zdarzeń onInstall , musisz zainstalować rozszerzenie w prawdziwym projekcie. To jednak dobrze, ponieważ dzięki dodaniu tej funkcji automatycznego uzupełniania rozszerzenie samouczka jest teraz kompletne i zawiera cały kod!

9. Wdróż w prawdziwym projekcie Firebase

Chociaż emulator rozszerzeń jest doskonałym narzędziem do szybkiej iteracji rozszerzenia podczas programowania, w pewnym momencie będziesz chciał wypróbować go w prawdziwym projekcie.

Aby to zrobić, skonfiguruj najpierw nowy projekt z włączonymi niektórymi usługami:

  1. W konsoli Firebase dodaj nowy projekt.
  2. Uaktualnij swój projekt do planu Blaze z płatnością zgodnie z rzeczywistym użyciem. Cloud Functions dla Firebase wymaga, aby Twój projekt miał konto rozliczeniowe, dlatego też potrzebujesz konta rozliczeniowego, aby zainstalować rozszerzenie.
  3. W swoim nowym projekcie włącz bazę danych czasu rzeczywistego .
  4. Ponieważ chcesz przetestować zdolność rozszerzenia do uzupełniania istniejących danych podczas instalacji, zaimportuj kilka przykładowych danych do instancji bazy danych czasu rzeczywistego:
    1. Pobierz niektóre dane początkowe RTDB .
    2. Na stronie Baza danych czasu rzeczywistego w konsoli Firebase kliknij (więcej) > Importuj JSON i wybierz właśnie pobrany plik.
  5. Aby umożliwić funkcji uzupełniania korzystanie z metody orderByChild , skonfiguruj bazę danych tak, aby indeksowała wiadomości na podstawie wartości upper :

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

Teraz zainstaluj rozszerzenie z lokalnego źródła w nowym projekcie:

  1. Utwórz nowy katalog dla swojego projektu Firebase:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Zainicjuj projekt Firebase w katalogu roboczym:

    firebase init database
    

    Po wyświetleniu monitu wybierz właśnie utworzony projekt.

  3. Zainstaluj rozszerzenie w lokalnym projekcie Firebase:

    firebase ext:install /path/to/rtdb-uppercase-messages
    

    Tutaj możesz zobaczyć, jak wygląda doświadczenie użytkownika podczas instalowania rozszerzenia za pomocą narzędzia Firebase CLI. Pamiętaj, aby wybrać „tak”, gdy narzędzie konfiguracyjne zapyta, czy chcesz uzupełnić istniejącą bazę danych.

    Po wybraniu opcji konfiguracji interfejs CLI Firebase zapisze Twoją konfigurację w katalogu extensions i zarejestruje lokalizację źródła rozszerzenia w pliku firebase.json . Łącznie te dwa rekordy nazywane są manifestem rozszerzeń . Użytkownicy mogą używać manifestu do zapisywania konfiguracji rozszerzeń i wdrażania jej w różnych projektach.

  4. Wdróż konfigurację rozszerzenia w aktywnym projekcie:

    firebase deploy --only extensions
    

Jeśli wszystko pójdzie dobrze, interfejs Firebase CLI powinien przesłać rozszerzenie do projektu i zainstalować je. Po zakończeniu instalacji zostanie uruchomione zadanie uzupełniania i za kilka minut Twoja baza danych zostanie zaktualizowana o wiadomości pisane wielkimi literami. Dodaj kilka nowych węzłów do bazy danych wiadomości i upewnij się, że rozszerzenie działa również w przypadku nowych wiadomości.

10. Napisz dokumentację

Zanim udostępnisz rozszerzenie użytkownikom, upewnij się, że udostępniasz wystarczającą dokumentację, aby mogli odnieść sukces.

Po zainicjowaniu projektu rozszerzenia interfejs CLI Firebase utworzył wersje pośrednie minimalnej wymaganej dokumentacji. Zaktualizuj te pliki, aby dokładnie odzwierciedlały utworzone rozszerzenie.

rozszerzenie.yaml

Aktualizowałeś już ten plik w miarę tworzenia tego rozszerzenia, więc nie musisz teraz wprowadzać żadnych dalszych aktualizacji.

Nie należy jednak zapominać o znaczeniu dokumentacji zawartej w tym pliku. Oprócz kluczowych informacji identyfikujących rozszerzenie — nazwy, opisu, autora i oficjalnej lokalizacji repozytorium — plik extension.yaml zawiera dostępną dla użytkownika dokumentację dotyczącą każdego zasobu i konfigurowalnego przez użytkownika parametru. Informacje te są wyświetlane użytkownikom w konsoli Firebase, Centrum rozszerzeń i interfejsie wiersza poleceń Firebase.

PREINSTALL.md

W tym pliku podaj informacje, których potrzebuje użytkownik przed zainstalowaniem rozszerzenia: krótko opisz, co robi rozszerzenie, wyjaśnij wszelkie wymagania wstępne i przekaż użytkownikowi informacje na temat konsekwencji rozliczeniowych instalacji rozszerzenia. Jeśli masz witrynę internetową zawierającą dodatkowe informacje, jest to również dobre miejsce na umieszczenie linku do niej.

Tekst tego pliku jest wyświetlany użytkownikowi w Extensions Hub i po wydaniu polecenia firebase ext:info .

Oto przykład pliku PREINSTALL:

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

Ten plik zawiera informacje przydatne dla użytkowników po pomyślnym zainstalowaniu rozszerzenia: na przykład dalsze kroki konfiguracji, przykład działania rozszerzenia i tak dalej.

Zawartość POSTINSTALL.md jest wyświetlana w konsoli Firebase po skonfigurowaniu i zainstalowaniu rozszerzenia. W tym pliku możesz odwoływać się do parametrów użytkownika, które zostaną zastąpione skonfigurowanymi wartościami.

Oto przykładowy plik poinstalacyjny rozszerzenia samouczka:

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

Powinieneś także udokumentować zmiany wprowadzane pomiędzy wydaniami rozszerzenia w pliku CHANGELOG.md .

Ponieważ przykładowe rozszerzenie nie było nigdy wcześniej publikowane, dziennik zmian zawiera tylko jeden wpis:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

Większość rozszerzeń udostępnia także plik Readme, z którego mogą korzystać użytkownicy odwiedzający repozytorium rozszerzenia. możesz zapisać ten plik ręcznie lub wygenerować plik Read Me za pomocą polecenia.

Na potrzeby tego przewodnika pomiń pisanie pliku Readme.

Dodatkowa dokumentacja

Dokumentacja omówiona powyżej to minimalny zestaw dokumentacji, jaki należy dostarczyć użytkownikom. Wiele rozszerzeń wymaga bardziej szczegółowej dokumentacji, aby użytkownicy mogli z nich pomyślnie korzystać. W takim przypadku należy napisać dodatkową dokumentację i umieścić ją w miejscu, do którego można wskazać użytkownikom.

Na potrzeby tego przewodnika pomiń pisanie bardziej rozbudowanej dokumentacji.

11. Opublikuj w Centrum rozszerzeń

Teraz, gdy kod Twojego rozszerzenia jest już kompletny i udokumentowany, możesz udostępnić je światu w Centrum rozszerzeń. Ale ponieważ jest to tylko tutorial, nie rób tego. Idź i zacznij pisać własne rozszerzenie, korzystając z tego, czego nauczyłeś się tutaj i z pozostałej dokumentacji wydawcy rozszerzeń Firebase, a także sprawdzając źródło oficjalnych rozszerzeń napisanych przez Firebase.

Gdy będziesz gotowy opublikować swoją pracę w Extensions Hub, możesz to zrobić w następujący sposób:

  1. Jeśli publikujesz swoje pierwsze rozszerzenie, zarejestruj się jako wydawca rozszerzenia . Rejestrując się jako wydawca rozszerzeń, tworzysz identyfikator wydawcy, który pozwala użytkownikom szybko zidentyfikować Cię jako autora rozszerzeń.
  2. Hostuj kod źródłowy rozszerzenia w publicznie weryfikowalnej lokalizacji. Jeśli Twój kod jest dostępny z weryfikowalnego źródła, Firebase może opublikować Twoje rozszerzenie bezpośrednio z tej lokalizacji. Dzięki temu będziesz mieć pewność, że opublikujesz aktualnie wydaną wersję rozszerzenia, a także pomożesz użytkownikom sprawdzić kod, który instalują w swoich projektach.

    Obecnie oznacza to udostępnienie rozszerzenia w publicznym repozytorium GitHub.

  3. Prześlij swoje rozszerzenie do Extensions Hub za pomocą polecenia firebase ext:dev:upload .

  4. Przejdź do panelu wydawcy w konsoli Firebase, znajdź właśnie przesłane rozszerzenie i kliknij „Opublikuj w Centrum rozszerzeń”. Wymaga to sprawdzenia przez nasz zespół recenzentów, co może zająć kilka dni. Po zatwierdzeniu rozszerzenie zostanie opublikowane w Centrum rozszerzeń. W przypadku odrzucenia otrzymasz wiadomość wyjaśniającą przyczynę; możesz następnie rozwiązać zgłoszone problemy i przesłać je ponownie do sprawdzenia.