Firebase con Vue 3: Firestore, VueFire ed emulatore locale

Firebase è uno dei modi più rapidi per avere un database ospitato in tempo reale. VueFire lo collega direttamente al sistema di reattività di Vue: i dati arrivano nei componenti e si aggiornano da soli, senza scrivere a mano sottoscrizioni e pulizia.

Firebase con Vue 3: Firestore, VueFire ed emulatore locale
Risposta rapida

Installa firebase e vuefire, inizializza l'applicazione con initializeApp e getFirestore, poi leggi una collezione con useCollection: la lista si aggiorna da sola. Sviluppa sull'emulatore Firestore locale invece che sul progetto di produzione.

Firebase offre un database, un’autenticazione e un hosting senza righe di server da scrivere. Collegato a Vue, dà una base in tempo reale le cui modifiche si propagano da sole nell’interfaccia. Ecco come cablarlo per bene con l’SDK modulare.

Firestore o Realtime Database?

Firebase propone due database. Realtime Database è il più vecchio: un grande albero JSON, query limitate. Cloud Firestore organizza i dati in collezioni di documenti, offre vere query composte e degli indici. Per un progetto nuovo scegli Firestore, ed è quello che fa questo articolo.

Installare

bash
npm install firebase vuefire

VueFire è il livello ufficiale che collega Firebase alla reattività di Vue. Non è obbligatorio, ma evita di scrivere a mano le sottoscrizioni e la loro pulizia.

Inizializzare

Crea il progetto nella console Firebase, aggiungi un’applicazione web e copia la configurazione. Mettila in un file dedicato:

src/firebase/index.js
import { initializeApp } from 'firebase/app'
import { getFirestore } from 'firebase/firestore'

export const firebaseApp = initializeApp({
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
  authDomain: 'mon-projet.firebaseapp.com',
  projectId: 'mon-projet'
})

export const db = getFirestore(firebaseApp)
La chiave API di Firebase è pubblica

Al contrario di quanto suggerisce il nome, non è un segreto: finisce nel bundle JavaScript e chiunque può leggerla. Identifica il progetto, non lo autorizza. La sicurezza dipende interamente dalle regole Firestore e dall’autenticazione. Scrivere le proprie regole è il vero lavoro di sicurezza, non nascondere questa chiave.

Collega poi VueFire all’applicazione:

src/main.js
import { createApp } from 'vue'
import { VueFire } from 'vuefire'
import App from './App.vue'
import { firebaseApp } from './firebase'

createApp(App)
  .use(VueFire, { firebaseApp })
  .mount('#app')

Leggere una collezione

useCollection restituisce un riferimento reattivo, popolato e poi tenuto aggiornato da Firestore:

src/components/ListeAvis.vue
<script setup>
import { collection } from 'firebase/firestore'
import { useCollection } from 'vuefire'
import { db } from '@/firebase'

const avis = useCollection(collection(db, 'avis'))
</script>

<template>
  <ul>
    <li v-for="a in avis" :key="a.id">{{ a.nom }} : {{ a.note }}/5</li>
  </ul>
</template>

Tutto qui: il ciclo v-for mostra la collezione come qualsiasi altro array. Apri la console Firebase e modifica un documento: la lista cambia nel browser senza ricaricare la pagina. VueFire chiude la sottoscrizione allo smontaggio del componente, il che evita la classica perdita dei listener dimenticati.

Per un solo documento, useDocument segue la stessa logica:

javascript
import { doc } from 'firebase/firestore'
import { useDocument } from 'vuefire'

const produit = useDocument(doc(db, 'produits', '2234'))

Filtrare e ordinare

Le query si compongono con query, where, orderBy e limit:

javascript
import { collection, limit, orderBy, query, where } from 'firebase/firestore'

const meilleursAvis = useCollection(
  query(
    collection(db, 'avis'),
    where('note', '>=', 4),
    orderBy('note', 'desc'),
    limit(10)
  )
)

Una query che combina un filtro e un ordinamento su campi diversi richiede un indice composito. Firestore la rifiuta e mostra nella console un link che crea l’indice con un clic: è il messaggio di errore più utile del prodotto.

Scrivere

Le scritture passano dalle funzioni dell’SDK, non da VueFire. Collegale a un form per creare documenti dall’interfaccia:

src/components/FormulaireAvis.vue
import {
  addDoc, collection, deleteDoc, doc, serverTimestamp, setDoc, updateDoc
} from 'firebase/firestore'
import { db } from '@/firebase'

// identificatore generato da Firestore
await addDoc(collection(db, 'avis'), {
  nom: 'Damien',
  note: 5,
  creeLe: serverTimestamp()
})

// identificatore scelto (crea o sostituisce)
await setDoc(doc(db, 'avis', 'avis-2234'), { nom: 'Damien', note: 5 })

// modificare alcuni campi
await updateDoc(doc(db, 'avis', 'avis-2234'), { note: 4 })

// eliminare
await deleteDoc(doc(db, 'avis', 'avis-2234'))

serverTimestamp() lascia a Firestore il compito di mettere la data lato server: l’orologio della macchina del visitatore non è affidabile.

Sviluppare sull’emulatore

Lavorare direttamente sul progetto di produzione rovina i dati e consuma la quota. La suite di emulatori Firebase fa girare Firestore in locale.

bash
npm install -D firebase-tools
npx firebase init emulators     # spuntare Firestore
npx firebase emulators:start --only firestore --project demo-boutique

Un identificatore di progetto che comincia per demo- dice all’emulatore di funzionare senza account né fatturazione.

Lato applicazione, collega l’SDK all’emulatore solo in sviluppo:

src/firebase/index.js
import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'

export const db = getFirestore(firebaseApp)

if (import.meta.env.DEV) {
  connectFirestoreEmulator(db, '127.0.0.1', 8080)
}
L’emulatore richiede Java 21

Da firebase-tools 15, una versione precedente del JDK fa fallire l’avvio con il messaggio « firebase-tools no longer supports Java version before 21 ». Controlla con java -version.

Le regole di sicurezza

Senza regole, il database è o chiuso o aperto a tutti. La modalità « test » proposta alla creazione scade dopo trenta giorni, non lasciarla in produzione.

firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    match /avis/{avisId} {
      // lettura pubblica
      allow read: if true;

      // scrittura riservata alle persone autenticate, sulla propria recensione
      allow create: if request.auth != null
                    && request.resource.data.auteurId == request.auth.uid;
      allow update, delete: if request.auth != null
                    && resource.data.auteurId == request.auth.uid;
    }
  }
}

Anche le regole si scrivono e si testano sull’emulatore, il che evita di scoprire un buco in produzione.

Che cosa è cambiato dall’SDK 8

Molti esempi ancora online usano la vecchia API a namespace. Dalla versione 9 di Firebase non funziona più così com’è:

javascript
// SDK vecchio (8 e precedenti) — non funziona più
import firebase from 'firebase'
const db = firebase.initializeApp(config).database()
db.ref('avis').push({ nom: 'Damien' })

// SDK modulare (9 e successivi)
import { initializeApp } from 'firebase/app'
import { addDoc, collection, getFirestore } from 'firebase/firestore'
const db = getFirestore(initializeApp(config))
await addDoc(collection(db, 'avis'), { nom: 'Damien' })

La suddivisione in funzioni importate non è cosmetica: permette al bundler di tenere solo quello che usi davvero. Su un’applicazione che si limita a leggere Firestore, la differenza di peso si vede.

Lato VueFire, la vecchia opzione firebase: { … } nei componenti e l’oggetto $firebaseRefs sono spariti: tutto passa da useCollection e useDocument.

Per approfondire

Questo montaggio dà per acquisiti i componenti e la reattività di Vue. Altrimenti comincia dal tutorial Vue 3 per principianti. Per condividere i dati Firebase tra componenti lontani fra loro, uno store Pinia che incapsula le chiamate Firestore è un buon schema.

Errori frequenti

Seguire un tutorial scritto per l'SDK 8 firebase.initializeApp(config).database() e l'oggetto globale firebase non funzionano più dalla versione 9. Tutto passa da funzioni importate.
Usare la vecchia API di VueFire L'opzione firebase: { … } nei componenti e $firebaseRefs sono spariti: usa useCollection e useDocument.
Credere che la chiave API sia un segreto Finisce nel bundle e da sola non autorizza niente. La sicurezza dipende dalle regole Firestore.
Lasciare le regole in modalità test Scadono dopo trenta giorni e fino ad allora lasciano il database aperto in scrittura.
Emulatore e versione di Java Da firebase-tools 15, un JDK precedente alla versione 21 fa fallire l'avvio.

FirebaseJavaScriptVue.js

Damien Flandrin Sviluppatore web dal 2010, creatore di Gekkode e di Email Impact. Ogni articolo è testato su un progetto reale prima della pubblicazione. Contatti
Newsletter

I nuovi test, tutorial e progetti, via e-mail.

Test riproducibili, codice versionato, risultati datati. Mai spam.