Firebase w aplikacji Vue 3: Firestore, VueFire i emulator

Firebase w aplikacji Vue 3: Firestore, VueFire i emulator
Szybka odpowiedź

Zainstaluj firebase i vuefire, zainicjuj aplikację przez initializeApp i getFirestore, a potem odczytaj kolekcję przez useCollection: lista aktualizuje się sama. Pracuj na lokalnym emulatorze Firestore, a nie na projekcie produkcyjnym.

Firebase daje bazę danych, uwierzytelnianie i hosting, bez pisania własnego backendu. Podpięty pod Vue, zachowuje się jak baza czasu rzeczywistego, której zmiany same przechodzą do interfejsu. Oto jak połączyć jedno z drugim porządnie, na modularnym SDK.

Firestore czy Realtime Database?

Firebase oferuje dwie bazy. Realtime Database jest starsza: jedno wielkie drzewo JSON i mocno ograniczone zapytania. Cloud Firestore układa dane w kolekcje dokumentów, obsługuje prawdziwe zapytania złożone i indeksy. Do nowego projektu bierz Firestore, i na nim opiera się ten artykuł.

Instalacja

bash
npm install firebase vuefire

VueFire to oficjalna warstwa spinająca Firebase z reaktywnością Vue. Nie jest obowiązkowa, ale oszczędza ręcznego pisania subskrypcji i ich sprzątania.

Inicjalizacja

Załóż projekt w konsoli Firebase, dodaj aplikację webową i skopiuj konfigurację. Trzymaj ją w osobnym pliku:

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)
Klucz API Firebase jest publiczny

Wbrew temu, co sugeruje nazwa, to nie jest sekret: trafia do bundle’a JavaScriptu i każdy może go odczytać. Identyfikuje projekt, ale niczego nie autoryzuje. Bezpieczeństwo opiera się w całości na regułach Firestore i uwierzytelnianiu. Prawdziwą robotą jest napisanie reguł, a nie ukrywanie tego klucza.

Następnie podepnij VueFire do aplikacji:

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')

Odczyt kolekcji

useCollection zwraca reaktywną referencję, którą Firestore najpierw zasila, a potem utrzymuje w aktualności:

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>

I to wszystko: pętla v-for wyświetla kolekcję jak zwykłą tablicę. Otwórz konsolę Firebase i zmień dokument, lista zmieni się w przeglądarce bez przeładowania. VueFire zamyka subskrypcję przy odmontowaniu komponentu, więc odpada klasyczny wyciek z zapomnianych listenerów.

Dla pojedynczego dokumentu useDocument działa tak samo:

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

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

Filtrowanie i sortowanie

Zapytania składa się z query, where, orderBy i 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)
  )
)

Zapytanie, które łączy filtr i sortowanie po różnych polach, wymaga indeksu złożonego. Firestore je odrzuci i wypisze w konsoli link tworzący ten indeks jednym kliknięciem, to najbardziej użyteczny komunikat błędu w całym produkcie.

Zapis

Zapisy idą przez funkcje SDK, nie przez VueFire. Podepnij je pod formularz, żeby tworzyć dokumenty z poziomu interfejsu:

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

// identyfikator wygenerowany przez Firestore
await addDoc(collection(db, 'avis'), {
  nom: 'Damien',
  note: 5,
  creeLe: serverTimestamp()
})

// identyfikator wybrany ręcznie (tworzy albo nadpisuje)
await setDoc(doc(db, 'avis', 'avis-2234'), { nom: 'Damien', note: 5 })

// zmiana wybranych pól
await updateDoc(doc(db, 'avis', 'avis-2234'), { note: 4 })

// usunięcie
await deleteDoc(doc(db, 'avis', 'avis-2234'))

serverTimestamp() zostawia stemplowanie czasem po stronie serwera: zegar maszyny odwiedzającego nie jest wiarygodny.

Praca na emulatorze

Praca wprost na projekcie produkcyjnym psuje dane i zjada limity. Pakiet emulatorów Firebase uruchamia Firestore lokalnie.

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

Identyfikator projektu zaczynający się od demo- mówi emulatorowi, żeby działał bez konta i bez rozliczeń.

Po stronie aplikacji podłącz SDK do emulatora wyłącznie w trybie deweloperskim:

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)
}
Emulator wymaga Javy 21

Od firebase-tools 15 starszy JDK wywala start komunikatem „firebase-tools no longer supports Java version before 21”. Sprawdź przez java -version.

Reguły bezpieczeństwa

Bez reguł baza jest albo zamknięta, albo otwarta dla wszystkich. Tryb testowy proponowany przy zakładaniu projektu wygasa po trzydziestu dniach, nie zostawiaj go na produkcji.

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

    match /avis/{avisId} {
      // odczyt publiczny
      allow read: if true;

      // zapis tylko dla zalogowanych, na własnej opinii
      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;
    }
  }
}

Reguły też pisze się i testuje na emulatorze, dzięki czemu dziury nie odkrywasz dopiero na produkcji.

Co się zmieniło od SDK 8

Sporo krążących po sieci przykładów wciąż korzysta ze starego API z przestrzeniami nazw. Od Firebase 9 taki kod po prostu nie działa:

javascript
// stary SDK (8 i starsze) — już nie działa
import firebase from 'firebase'
const db = firebase.initializeApp(config).database()
db.ref('avis').push({ nom: 'Damien' })

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

Rozbicie na importowane funkcje nie jest kosmetyką: pozwala bundlerowi zostawić tylko to, czego naprawdę używasz. W aplikacji, która wyłącznie czyta z Firestore, różnica w wadze jest wyraźna.

Po stronie VueFire zniknęły stara opcja firebase: { … } w komponentach i obiekt $firebaseRefs: wszystko idzie przez useCollection i useDocument.

Co dalej

Ten montaż zakłada, że komponenty i reaktywność Vue masz już opanowane. Jeśli nie, zacznij od kursu Vue 3 dla początkujących. Do dzielenia danych z Firebase między odległymi komponentami dobrym wzorcem jest store Pinia, który opakowuje wywołania Firestore.

Częste błędy

Pójście za tutorialem napisanym pod SDK 8 firebase.initializeApp(config).database() i globalny obiekt firebase nie działają od wersji 9. Wszystko idzie przez importowane funkcje.
Używanie starego API VueFire Opcja firebase: { … } w komponentach i $firebaseRefs zniknęły: używaj useCollection i useDocument.
Traktowanie klucza API jak sekretu Trafia do bundle'a i sam z siebie niczego nie autoryzuje. Bezpieczeństwo opiera się na regułach Firestore.
Zostawienie reguł w trybie testowym Wygasają po trzydziestu dniach, a do tego czasu baza jest otwarta na zapis.
Emulator a wersja Javy Od firebase-tools 15 JDK starszy niż 21 wywala start.

FirebaseJavaScriptVue.js

Damien Flandrin Web developer od 2010 roku, twórca Gekkode i Email Impact. Każdy artykuł jest sprawdzany na prawdziwym projekcie przed publikacją. Kontakt
Newsletter

Nowe testy, poradniki i projekty — e-mailem.

Powtarzalne testy, wersjonowany kod, datowane wyniki. Nigdy spamu.