Inizia a creare un'estensione

Questa pagina ti guida attraverso i passaggi necessari per creare una semplice estensione Firebase, che puoi installare nei tuoi progetti o condividere con altri. Questo semplice esempio di estensione Firebase controllerà i messaggi nel tuo database Realtime e li convertirà in maiuscolo.

1. Configura il tuo ambiente e inizializza un progetto

Prima di poter iniziare a creare un'estensione, dovrai configurare un ambiente di creazione con gli strumenti richiesti.

  1. Installa Node.js 16 o versione successiva. Un modo per installare Node è utilizzare nvm (o nvm-windows ).

  2. Installa o aggiorna alla versione più recente della CLI Firebase . Per installare o aggiornare utilizzando npm , esegui questo comando:

    npm install -g firebase-tools
    

Ora utilizza la CLI Firebase per inizializzare un nuovo progetto di estensione:

  1. Crea una directory per la tua estensione e cd :

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
    
  2. Esegui il comando ext:dev:init della CLI di Firebase:

    firebase ext:dev:init
    

    Quando richiesto, scegli JavaScript come linguaggio per le funzioni (ma tieni presente che puoi anche utilizzare TypeScript quando sviluppi la tua estensione) e, quando ti viene chiesto di installare le dipendenze, rispondi "sì". (Accetta le impostazioni predefinite per qualsiasi altra opzione.) Questo comando imposterà una base di codice scheletro per una nuova estensione, da cui potrai iniziare a sviluppare la tua estensione.

2. Prova l'estensione di esempio utilizzando l'emulatore

Quando la CLI Firebase ha inizializzato la nuova directory delle estensioni, ha creato una semplice funzione di esempio e una directory di integration-tests che contiene i file necessari per eseguire un'estensione utilizzando la suite di emulatore Firebase.

Prova a eseguire l'estensione di esempio nell'emulatore:

  1. Passare alla directory integration-tests :

    cd functions/integration-tests
    
  2. Avvia l'emulatore con un progetto demo:

    firebase emulators:start --project=demo-test
    

    L'emulatore carica l'estensione in un progetto "fittizio" predefinito ( demo-test ). L'estensione finora consiste in una singola funzione attivata da HTTP, greetTheWorld , che restituisce un messaggio "ciao mondo" quando si accede.

  3. Con l'emulatore ancora in esecuzione, prova la funzione greetTheWorld dell'estensione visitando l'URL stampato all'avvio.

    Il tuo browser visualizza il messaggio "Hello World da greet-the-world".

  4. Il codice sorgente per questa funzione si trova nella directory delle functions dell'estensione. Apri il sorgente nell'editor o nell'IDE di tua scelta:

    funzioni/index.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. Mentre l'emulatore è in esecuzione, ricaricherà automaticamente tutte le modifiche apportate al codice Funzioni. Prova ad apportare una piccola modifica alla funzione greetTheWorld :

    funzioni/index.js

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

    Salva le modifiche. L'emulatore ricaricherà il tuo codice e ora, quando visiti l'URL della funzione, vedrai il saluto aggiornato.

3. Aggiungi le informazioni di base a extension.yaml

Ora che hai configurato un ambiente di sviluppo e stai eseguendo l'emulatore delle estensioni, puoi iniziare a scrivere la tua estensione.

Come primo passo, modifica i metadati dell'estensione predefinita per riflettere l'estensione che desideri scrivere invece di greet-the-world . Questi metadati sono archiviati nel file extension.yaml .

  1. Apri extension.yaml nel tuo editor e sostituisci l'intero contenuto del file con quanto segue:

    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
    

    Nota la convenzione di denominazione utilizzata nel campo name : le estensioni ufficiali Firebase sono denominate con un prefisso che indica il prodotto Firebase principale su cui opera l'estensione, seguito da una descrizione di ciò che fa l'estensione. Dovresti usare la stessa convenzione nelle tue estensioni.

  2. Dato che hai cambiato il nome della tua estensione, dovresti aggiornare anche la configurazione dell'emulatore con il nuovo nome:

    1. functions/integration-tests/firebase.json , cambia greet-the-world in rtdb-uppercase-messages .
    2. functions/integration-tests/extensions/greet-the-world.env functions/integration-tests/extensions/rtdb-uppercase-messages.env .

Nel codice dell'estensione sono ancora presenti alcuni residui dell'estensione greet-the-world , ma per ora lasciali stare. Li aggiornerai nelle prossime sezioni.

4. Scrivi una funzione Cloud e dichiarala come risorsa di estensione

Ora puoi iniziare a scrivere del codice. In questo passaggio, scriverai una Cloud Function che esegue il compito principale della tua estensione, ovvero controllare i messaggi del tuo Realtime Database e convertirli in maiuscolo.

  1. Apri il sorgente delle funzioni dell'estensione (nella directory delle functions dell'estensione) nell'editor o nell'IDE di tua scelta. Sostituisci il suo contenuto con quanto segue:

    funzioni/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);
    });
    

    La vecchia funzione, che hai sostituito, era una funzione attivata da HTTP, che veniva eseguita quando si accedeva a un endpoint HTTP. La nuova funzione viene attivata da eventi del database in tempo reale: controlla i nuovi elementi in un percorso particolare e, quando ne viene rilevato uno, riscrive la versione maiuscola del valore nel database.

    A proposito, questo nuovo file utilizza la sintassi del modulo ECMAScript ( import ed export ) invece di CommonJS ( require ). Per utilizzare i moduli ES in Node, specifica "type": "module" in functions/package.json :

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      …
    }
    
  2. Ogni funzione nella tua estensione deve essere dichiarata nel file extension.yaml . L'estensione di esempio ha dichiarato greetTheWorld come l'unica funzione Cloud dell'estensione; ora che lo hai sostituito con makeuppercase , devi aggiornare anche la sua dichiarazione.

    Apri extension.yaml e aggiungi un campo 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. Poiché la tua estensione ora utilizza Realtime Database come trigger, devi aggiornare la configurazione dell'emulatore per eseguire l'emulatore RTDB insieme all'emulatore Cloud Functions:

    1. Se l'emulatore è ancora in esecuzione, interrompilo premendo Ctrl-C.

    2. Dalla directory functions/integration-tests , esegui il comando seguente:

      firebase init emulators
      

      Quando richiesto, salta la configurazione di un progetto predefinito, quindi seleziona le funzioni e gli emulatori di database. Accetta le porte predefinite e consenti allo strumento di configurazione di scaricare tutti i file richiesti.

    3. Riavviare l'emulatore:

      firebase emulators:start --project=demo-test
      
  4. Prova la tua estensione aggiornata:

    1. Apri l'interfaccia utente dell'emulatore di database utilizzando il collegamento stampato dall'emulatore quando lo hai avviato.

    2. Modifica il nodo radice del database:

      • Campo: messages
      • Tipo: json
      • Valore: {"11": {"original": "recipe"}}

      Se tutto è impostato correttamente, quando salvi le modifiche al database, la funzione makeuppercase dell'estensione dovrebbe attivarsi e aggiungere un record figlio al messaggio 11 con il contenuto "upper": "RECIPE" . Dai un'occhiata ai registri e alle schede del database dell'interfaccia utente dell'emulatore per confermare i risultati attesi.

    3. Prova ad aggiungere altri figli al nodo messages ( {"original":"any text"} ). Ogni volta che aggiungi un nuovo record, l'estensione dovrebbe aggiungere un campo uppercase contenente il contenuto in maiuscolo del campo original .

Ora disponi di un'estensione completa, anche se semplice, che opera su un'istanza RTDB. Nelle sezioni che seguono, perfezionerai questa estensione con alcune funzionalità aggiuntive. Quindi, avrai l'estensione pronta per essere distribuita ad altri e, infine, imparerai come pubblicare la tua estensione su Extensions Hub.

5. Dichiarare API e ruoli

Firebase concede a ciascuna istanza di un'estensione installata un accesso limitato al progetto e ai relativi dati utilizzando un account di servizio per istanza. Ogni account dispone del set minimo di autorizzazioni necessarie per operare. Per questo motivo, devi dichiarare esplicitamente tutti i ruoli IAM richiesti dalla tua estensione; quando gli utenti installano la tua estensione, Firebase crea un account di servizio con questi ruoli concessi e lo utilizza per eseguire l'estensione.

Non è necessario dichiarare ruoli per attivare gli eventi di un prodotto, ma è necessario dichiarare un ruolo per interagire con esso in altro modo. Poiché la funzione che hai aggiunto nell'ultimo passaggio scrive su Realtime Database, devi aggiungere la seguente dichiarazione a extension.yaml :

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

Allo stesso modo, dichiari le API di Google utilizzate da un'estensione nel campo apis . Quando gli utenti installano la tua estensione, verrà loro chiesto se desiderano abilitare automaticamente queste API per il loro progetto. Questo in genere è necessario solo per le API Google non Firebase e non è necessario per questa guida.

6. Definire i parametri configurabili dall'utente

La funzione creata negli ultimi due passaggi ha monitorato una posizione RTDB specifica per i messaggi in arrivo. A volte, guardare una posizione specifica è davvero ciò che desideri, ad esempio quando la tua estensione opera su una struttura di database che utilizzi esclusivamente per la tua estensione. Tuttavia, nella maggior parte dei casi, vorrai rendere questi valori configurabili dagli utenti che installano la tua estensione nei loro progetti. In questo modo, gli utenti possono utilizzare la tua estensione per lavorare con la configurazione del database esistente.

Rendi configurabile dall'utente il percorso che l'estensione controlla per i nuovi messaggi:

  1. Nel file extension.yaml , aggiungi una sezione 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
    

    Ciò definisce un nuovo parametro di stringa che agli utenti verrà richiesto di impostare quando installano l'estensione.

  2. Sempre nel file extension.yaml , torna alla dichiarazione makeuppercase e modifica il campo resource come segue:

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

    Il token ${param:MESSAGE_PATH} è un riferimento al parametro che hai appena definito. Quando l'estensione viene eseguita, questo token verrà sostituito da qualsiasi valore configurato dall'utente per quel parametro, con il risultato che la funzione makeuppercase ascolterà il percorso specificato dall'utente. Puoi utilizzare questa sintassi per fare riferimento a qualsiasi parametro definito dall'utente ovunque in extension.yaml (e in POSTINSTALL.md , ne parleremo più avanti).

  3. È inoltre possibile accedere ai parametri definiti dall'utente dal codice delle funzioni.

    Nella funzione che hai scritto nell'ultima sezione, hai codificato il percorso per verificare le modifiche. Modificare invece la definizione del trigger per fare riferimento al valore definito dall'utente:

    funzioni/index.js

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

    Tieni presente che in Firebase Extensions questa modifica è puramente a scopo di documentazione: quando una funzione Cloud viene distribuita come parte di un'estensione, utilizza la definizione di trigger dal file extension.yaml e ignora il valore specificato nella definizione della funzione. Tuttavia, è una buona idea documentare nel codice da dove proviene questo valore.

  4. Potresti trovare deludente apportare una modifica al codice che non abbia alcun effetto sul runtime, ma la lezione importante da imparare è che puoi accedere a qualsiasi parametro definito dall'utente nel codice della funzione e utilizzarlo come valore ordinario nella logica della funzione. Come cenno a questa funzionalità, aggiungi la seguente istruzione di log per dimostrare che stai effettivamente accedendo al valore definito dall'utente:

    funzioni/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.
        ...
    
  5. Normalmente, agli utenti viene richiesto di fornire valori per i parametri quando installano un'estensione. Quando utilizzi l'emulatore per test e sviluppo, tuttavia, salti il ​​processo di installazione e fornisci invece valori per i parametri definiti dall'utente utilizzando un file env .

    functions/integration-tests/extensions/rtdb-uppercase-messages.env e sostituisci la definizione GREETING con la seguente:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Nota che il percorso sopra è diverso dal percorso predefinito e dal percorso definito in precedenza; questo è solo per dimostrare a te stesso quando provi l'estensione aggiornata che la tua definizione sta avendo effetto.

  6. Ora riavvia l'emulatore e visita nuovamente l'interfaccia utente dell'emulatore del database.

    Modifica il nodo radice del database, utilizzando il percorso definito sopra:

    • Campo: msgs
    • Tipo: json
    • Valore: {"11": {"original": "recipe"}}

    Quando salvi le modifiche al database, la funzione makeuppercase dell'estensione dovrebbe attivarsi come prima, ma ora dovrebbe anche stampare il parametro definito dall'utente nel registro della console.

7. Fornire hook di eventi per la logica definita dall'utente

Hai già visto, come autore di estensioni, come un prodotto Firebase può attivare la logica fornita dall'estensione: la creazione di nuovi record in Realtime Database attiva la tua funzione makeuppercase . La tua estensione può avere una relazione analoga con gli utenti che installano la tua estensione: la tua estensione può attivare la logica definita dall'utente .

Un'estensione può fornire hook sincroni , hook asincroni o entrambi. Gli hook sincroni offrono agli utenti un modo per eseguire attività che bloccano il completamento di una delle funzioni dell'estensione. Ciò può essere utile, ad esempio, per offrire agli utenti la possibilità di eseguire una preelaborazione personalizzata prima che un'estensione esegua il proprio lavoro.

In questa guida aggiungerai un hook asincrono alla tua estensione, che consentirà agli utenti di definire i propri passaggi di elaborazione da eseguire dopo che l'estensione avrà scritto il messaggio in maiuscolo su Realtime Database. Gli hook asincroni utilizzano Eventarc per attivare funzioni definite dall'utente. Le estensioni dichiarano i tipi di eventi che emettono e, quando gli utenti installano l'estensione, scelgono i tipi di eventi a cui sono interessati. Se scelgono almeno un evento, Firebase fornirà un canale Eventarc per l'estensione come parte del processo di installazione . Gli utenti possono quindi distribuire le proprie funzioni cloud che restano in ascolto su quel canale e si attivano quando l'estensione pubblica nuovi eventi.

Seguire questi passaggi per aggiungere un hook asincrono:

  1. Nel file extension.yaml , aggiungi la seguente sezione, che dichiara l'unico tipo di evento emesso dall'estensione:

    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.
    

    I tipi di eventi devono essere universalmente unici; Per garantire l'unicità, assegna sempre un nome agli eventi utilizzando il seguente formato: <publisher-id>.<extension-id>.<version>.<description> . (Non hai ancora un ID editore, quindi per ora utilizza semplicemente test-publisher .)

  2. Alla fine della funzione makeuppercase , aggiungi del codice che pubblica un evento del tipo che hai appena dichiarato:

    funzioni/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,
        },
      });
    

    Questo codice di esempio sfrutta il fatto che la variabile di ambiente EVENTARC_CHANNEL è definita solo quando l'utente ha abilitato almeno un tipo di evento. se EVENTARC_CHANNEL non è definito, il codice non tenta di pubblicare alcun evento.

    Puoi allegare informazioni aggiuntive a un evento Eventarc. Nell'esempio precedente, l'evento ha un campo subject che contiene un riferimento al valore appena creato e un payload data che contiene i messaggi originali e in maiuscolo. Le funzioni definite dall'utente che attivano l'evento possono utilizzare queste informazioni.

  3. Normalmente, le variabili d'ambiente EVENTARC_CHANNEL e EXT_SELECTED_EVENTS vengono definite in base alle opzioni selezionate dall'utente durante l'installazione. Per testare con l'emulatore, definisci manualmente queste variabili nel file rtdb-uppercase-messages.env :

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

A questo punto, hai completato i passaggi necessari per aggiungere un hook di evento asincrono alla tua estensione.

Per provare questa nuova funzionalità che hai appena implementato, nei prossimi passaggi, assumi il ruolo di un utente che sta installando l'estensione:

  1. Dalla directory functions/integration-tests , inizializza un nuovo progetto Firebase:

    firebase init functions
    

    Quando richiesto, rifiuta di impostare un progetto predefinito, seleziona JavaScript come linguaggio Cloud Functions e installa le dipendenze richieste. Questo progetto rappresenta il progetto di un utente su cui è installata la tua estensione.

  2. Modifica integration-tests/functions/index.js e incolla il seguente codice:

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

    Questo è un esempio di una funzione di post-elaborazione che un utente potrebbe scrivere. In questo caso, la funzione ascolta l'estensione per pubblicare un evento complete e, una volta attivata, aggiunge tre punti esclamativi al nuovo messaggio in maiuscolo.

  3. Riavviare l'emulatore. L'emulatore caricherà le funzioni dell'estensione così come la funzione di post-elaborazione definita dall'utente.

  4. Visita l'interfaccia utente dell'emulatore di database e modifica il nodo radice del database, utilizzando il percorso definito sopra:

    • Campo: msgs
    • Tipo: json
    • Valore: {"11": {"original": "recipe"}}

    Quando salvi le modifiche al database, la funzione makeuppercase dell'estensione e la funzione extraemphasis dell'utente dovrebbero attivarsi in sequenza, facendo sì che il campo upper ottenga il valore RECIPE!!! .

8. Aggiungi gestori di eventi del ciclo di vita

L'estensione che hai scritto finora elabora i messaggi man mano che vengono creati. Ma cosa succede se i tuoi utenti dispongono già di un database di messaggi quando installano l'estensione? Firebase Extensions dispone di una funzionalità chiamata hook degli eventi del ciclo di vita che puoi utilizzare per attivare azioni quando l'estensione viene installata, aggiornata o riconfigurata. In questa sezione utilizzerai gli hook degli eventi del ciclo di vita per riempire il database dei messaggi esistente di un progetto con messaggi in maiuscolo quando un utente installa la tua estensione.

Firebase Extensions utilizza Cloud Tasks per eseguire i gestori di eventi del ciclo di vita. Puoi definire i gestori eventi utilizzando Cloud Functions; ogni volta che un'istanza della tua estensione raggiunge uno degli eventi del ciclo di vita supportati, se hai definito un gestore, il gestore verrà aggiunto a una coda di Cloud Tasks. Cloud Tasks eseguirà quindi il gestore in modo asincrono. Mentre un gestore eventi del ciclo di vita è in esecuzione, la console Firebase segnalerà all'utente che l'istanza dell'estensione ha un'attività di elaborazione in corso. Spetta alla funzione del tuo gestore segnalare all'utente lo stato in corso e il completamento dell'attività.

Per aggiungere un gestore eventi del ciclo di vita che riempia i messaggi esistenti, procedi come segue:

  1. Definisci una nuova funzione Cloud che viene attivata dagli eventi della coda di attività:

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

    Tieni presente che la funzione elabora solo alcuni record prima di aggiungersi nuovamente alla coda delle attività. Questa è una strategia comunemente utilizzata per gestire attività di elaborazione che non possono essere completate entro la finestra di timeout di una Funzione Cloud. Poiché non puoi prevedere quanti messaggi un utente potrebbe già avere nel proprio database quando installa la tua estensione, questa strategia è una buona soluzione.

  2. Nel file extension.yaml , dichiara la funzione di backfill come risorsa di estensione con la proprietà taskQueueTrigger :

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

    Quindi dichiara la funzione come gestore per l'evento del ciclo di vita onInstall :

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. Sebbene sia utile eseguire il backfill dei messaggi esistenti, l'estensione potrebbe comunque funzionare senza di essa. In situazioni come questa, dovresti rendere facoltativa l'esecuzione dei gestori di eventi del ciclo di vita.

    Per fare ciò, aggiungi un nuovo parametro a 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
    

    Quindi all'inizio della funzione di recupero, controlla il valore del parametro DO_BACKFILL ed esci prima se non è impostato:

    funzioni/index.js

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

Con le modifiche di cui sopra, l'estensione ora convertirà i messaggi esistenti in maiuscolo quando verrà installata.

Fino a questo punto, hai utilizzato l'emulatore di estensione per sviluppare la tua estensione e testare le modifiche in corso. Tuttavia, l'emulatore dell'estensione salta il processo di installazione, quindi per testare il gestore eventi onInstall , dovrai installare l'estensione in un progetto reale. Meglio così, dato che con l'aggiunta di questa funzionalità di recupero automatico, l'estensione del tutorial è ora completa di codice!

9. Distribuisci in un vero progetto Firebase

Sebbene l'emulatore di estensioni sia un ottimo strumento per eseguire rapidamente l'iterazione di un'estensione durante lo sviluppo, ad un certo punto vorrai provarlo in un progetto reale.

Per fare ciò, imposta prima un nuovo progetto con alcuni servizi abilitati:

  1. Nella console Firebase , aggiungi un nuovo progetto.
  2. Aggiorna il tuo progetto al piano Blaze con pagamento in base al consumo. Cloud Functions for Firebase richiede che il tuo progetto disponga di un account di fatturazione, quindi avrai bisogno anche di un account di fatturazione per installare un'estensione.
  3. Nel tuo nuovo progetto, abilita Real-time Database .
  4. Poiché desideri testare la capacità della tua estensione di eseguire il backfill dei dati esistenti al momento dell'installazione, importa alcuni dati di esempio nell'istanza del database in tempo reale:
    1. Scarica alcuni dati RTDB seed .
    2. Nella pagina Database in tempo reale della console Firebase, fai clic su (altro) > Importa JSON e seleziona il file appena scaricato.
  5. Per consentire alla funzione di recupero di utilizzare il metodo orderByChild , configurare il database per indicizzare i messaggi sul valore di upper :

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

Ora installa la tua estensione dalla sorgente locale nel nuovo progetto:

  1. Crea una nuova directory per il tuo progetto Firebase:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Inizializza un progetto Firebase nella directory di lavoro:

    firebase init database
    

    Quando richiesto, seleziona il progetto appena creato.

  3. Installa l'estensione nel tuo progetto Firebase locale:

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

    Qui puoi vedere com'è l'esperienza utente quando installi un'estensione utilizzando lo strumento CLI Firebase. Assicurati di selezionare "sì" quando lo strumento di configurazione ti chiede se desideri riempire il database esistente.

    Dopo aver selezionato le opzioni di configurazione, la CLI Firebase salverà la configurazione nella directory extensions e registrerà la posizione di origine dell'estensione nel file firebase.json . Collettivamente, questi due record sono chiamati manifest delle estensioni . Gli utenti possono utilizzare il manifest per salvare la configurazione delle estensioni e distribuirlo su diversi progetti.

  4. Distribuisci la configurazione dell'estensione al tuo progetto live:

    firebase deploy --only extensions
    

Se tutto va bene, la CLI di Firebase dovrebbe caricare la tua estensione nel tuo progetto e installarla. Al termine dell'installazione, verrà eseguita l'attività di recupero e, in pochi minuti, il database verrà aggiornato con messaggi in maiuscolo. Aggiungi alcuni nuovi nodi al database dei messaggi e assicurati che l'estensione funzioni anche per i nuovi messaggi.

10. Scrivere la documentazione

Prima di condividere la tua estensione con gli utenti, assicurati di fornire documentazione sufficiente affinché possano avere successo.

Quando hai inizializzato il progetto di estensione, la CLI di Firebase ha creato versioni stub della documentazione minima richiesta. Aggiorna questi file per riflettere accuratamente l'estensione che hai creato.

estensione.yaml

Hai già aggiornato questo file man mano che hai sviluppato questa estensione, quindi non è necessario apportare altri aggiornamenti in questo momento.

Tuttavia, non trascurare l'importanza della documentazione contenuta in questo file. Oltre alle informazioni identificative cruciali di un'estensione (nome, descrizione, autore, posizione ufficiale del repository), il file extension.yaml contiene documentazione rivolta all'utente per ogni risorsa e parametro configurabile dall'utente. Queste informazioni vengono presentate agli utenti nella console Firebase, nell'hub estensioni e nella CLI Firebase.

PREINSTALL.md

In questo file, fornisci le informazioni di cui l'utente ha bisogno prima di installare l'estensione: descrivi brevemente cosa fa l'estensione, spiega eventuali prerequisiti e fornisci all'utente informazioni sulle implicazioni di fatturazione dell'installazione dell'estensione. Se hai un sito web con informazioni aggiuntive, anche questo è un buon posto per collegarlo.

Il testo di questo file viene visualizzato all'utente nell'hub estensioni e dal comando firebase ext:info .

Ecco un esempio di file 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

Questo file contiene informazioni utili per gli utenti dopo aver installato correttamente l'estensione: ad esempio, passaggi di configurazione successivi, un esempio dell'estensione in azione e così via.

Il contenuto di POSTINSTALL.md viene visualizzato nella console Firebase dopo la configurazione e l'installazione di un'estensione. È possibile fare riferimento ai parametri utente in questo file e verranno sostituiti dai valori configurati.

Ecco un esempio di file post-installazione per l'estensione del tutorial:

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

Dovresti anche documentare le modifiche apportate tra i rilasci di un'estensione nel file CHANGELOG.md .

Poiché l'estensione di esempio non è mai stata pubblicata prima, il registro delle modifiche ha una sola voce:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

La maggior parte delle estensioni fornisce anche un file leggimi a vantaggio degli utenti che visitano il repository dell'estensione. puoi scrivere questo file a mano o generare un leggimi usando il comando.

Ai fini di questa guida, salta la scrittura di un file leggimi.

Documentazione aggiuntiva

La documentazione discussa sopra è l'insieme minimo di documentazione che dovresti fornire agli utenti. Molte estensioni richiedono una documentazione più dettagliata affinché gli utenti possano utilizzarle con successo. In questo caso, dovresti scrivere documentazione aggiuntiva e ospitarla da qualche parte a cui puoi indirizzare gli utenti.

Ai fini di questa guida, evita di scrivere documentazione più estesa.

11. Pubblica su Extensions Hub

Ora che il codice della tua estensione è completo e documentato, sei pronto per condividerlo con il mondo su Extensions Hub. Ma poiché questo è solo un tutorial, non farlo davvero. Vai e inizia a scrivere la tua estensione utilizzando ciò che hai imparato qui e nel resto della documentazione dell'editore di Firebase Extensions ed esaminando la fonte delle estensioni ufficiali, scritte da Firebase.

Quando sarai pronto per pubblicare il tuo lavoro su Extensions Hub, ecco come lo farai:

  1. Se stai pubblicando la tua prima estensione, registrati come editore di estensioni . Quando ti registri come editore di estensioni, crei un ID editore che consente agli utenti di identificarti rapidamente come autore delle tue estensioni.
  2. Ospita il codice sorgente della tua estensione in una posizione verificabile pubblicamente. Quando il tuo codice è disponibile da una fonte verificabile, Firebase può pubblicare la tua estensione direttamente da questa posizione. Ciò aiuta a garantire che stai pubblicando la versione attualmente rilasciata della tua estensione e aiuta gli utenti consentendo loro di esaminare il codice che stanno installando nei loro progetti.

    Attualmente, ciò significa rendere la tua estensione disponibile in un repository GitHub pubblico.

  3. Carica la tua estensione nell'hub estensioni utilizzando il comando firebase ext:dev:upload .

  4. Vai alla dashboard del tuo editore nella console Firebase, trova l'estensione che hai appena caricato e fai clic su "Pubblica nell'hub delle estensioni". Ciò richiede una revisione da parte del nostro staff di revisione, che può richiedere alcuni giorni. Se approvata, l'estensione verrà pubblicata nell'hub estensioni. In caso di rifiuto riceverai un messaggio che ne spiega il motivo; è quindi possibile risolvere i problemi segnalati e inviarli nuovamente per la revisione.