
Instala o firebase e o vuefire, inicializa a aplicação com initializeApp e getFirestore, depois lê uma coleção com useCollection: a lista atualiza-se sozinha. Desenvolve contra o emulador Firestore local em vez do projeto de produção.
O Firebase fornece uma base de dados, uma autenticação e um alojamento sem que tenhas de escrever um servidor. Ligado ao Vue, dá uma base em tempo real cujas alterações se propagam sozinhas até à interface. Eis como o montar como deve ser, com o SDK modular.
Firestore ou Realtime Database?
O Firebase propõe duas bases. A Realtime Database é a mais antiga: uma grande árvore JSON e consultas limitadas. A Cloud Firestore organiza os dados em coleções de documentos, oferece verdadeiras consultas compostas e índices. Para um projeto novo, escolhe o Firestore, é o que este artigo faz.
Instalar
npm install firebase vuefireO VueFire é a camada oficial que liga o Firebase à reatividade do Vue. Não é obrigatória, mas evita escrever à mão as subscrições e a respetiva limpeza.
Inicializar
Cria o projeto na consola do Firebase, acrescenta uma aplicação web e copia a configuração. Guarda-a num ficheiro dedicado:
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)Ao contrário do que o nome sugere, não é um segredo: vai no bundle JavaScript e qualquer pessoa a pode ler. Identifica o projeto, não o autoriza. A segurança assenta inteiramente nas regras do Firestore e na autenticação. Escrever as regras é o verdadeiro trabalho de segurança, não esconder esta chave.
Liga depois o VueFire à aplicação:
import { createApp } from 'vue'
import { VueFire } from 'vuefire'
import App from './App.vue'
import { firebaseApp } from './firebase'
createApp(App)
.use(VueFire, { firebaseApp })
.mount('#app')Ler uma coleção
O useCollection devolve uma referência reativa, preenchida e depois mantida atualizada pelo Firestore:
<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>É tudo: o ciclo v-for mostra a coleção como qualquer array. Abre a consola do Firebase e altera um documento: a lista muda no navegador sem recarregar. O VueFire fecha a subscrição quando o componente é desmontado, o que evita a fuga clássica dos listeners esquecidos.
Para um documento isolado, o useDocument segue a mesma lógica:
import { doc } from 'firebase/firestore'
import { useDocument } from 'vuefire'
const produit = useDocument(doc(db, 'produits', '2234'))Filtrar e ordenar
As consultas compõem-se com query, where, orderBy e limit:
import { collection, limit, orderBy, query, where } from 'firebase/firestore'
const meilleursAvis = useCollection(
query(
collection(db, 'avis'),
where('note', '>=', 4),
orderBy('note', 'desc'),
limit(10)
)
)Uma consulta que combina um filtro e uma ordenação em campos diferentes exige um índice composto. O Firestore recusa a consulta e mostra na consola uma ligação que cria o índice num clique, é a mensagem de erro mais útil do produto.
Escrever
As escritas passam pelas funções do SDK, não pelo VueFire. Liga-as a um formulário para criar documentos a partir da interface:
import {
addDoc, collection, deleteDoc, doc, serverTimestamp, setDoc, updateDoc
} from 'firebase/firestore'
import { db } from '@/firebase'
// identificador gerado pelo Firestore
await addDoc(collection(db, 'avis'), {
nom: 'Damien',
note: 5,
creeLe: serverTimestamp()
})
// identificador escolhido (cria ou substitui)
await setDoc(doc(db, 'avis', 'avis-2234'), { nom: 'Damien', note: 5 })
// alterar alguns campos
await updateDoc(doc(db, 'avis', 'avis-2234'), { note: 4 })
// apagar
await deleteDoc(doc(db, 'avis', 'avis-2234'))O serverTimestamp() deixa o Firestore datar do lado do servidor: a hora da máquina do visitante não é de confiança.
Desenvolver contra o emulador
Trabalhar diretamente no projeto de produção estraga os dados e consome a quota. A suite de emuladores do Firebase põe o Firestore a correr localmente.
npm install -D firebase-tools
npx firebase init emulators # assinalar o Firestore
npx firebase emulators:start --only firestore --project demo-boutiqueUm identificador de projeto começado por demo- diz ao emulador para funcionar sem conta nem faturação.
Do lado da aplicação, liga o SDK ao emulador apenas em desenvolvimento:
import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'
export const db = getFirestore(firebaseApp)
if (import.meta.env.DEV) {
connectFirestoreEmulator(db, '127.0.0.1', 8080)
}Desde o firebase-tools 15, uma versão anterior do JDK faz falhar o arranque com a mensagem «firebase-tools no longer supports Java version before 21». Confirma com java -version.
As regras de segurança
Sem regras, a base está fechada ou aberta a toda a gente. O modo «teste» proposto na criação expira ao fim de trinta dias, não o deixes em produção.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /avis/{avisId} {
// leitura pública
allow read: if true;
// escrita reservada a quem tem sessão iniciada, sobre a sua própria avaliação
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;
}
}
}As regras também se escrevem e testam contra o emulador, o que evita descobrir um buraco em produção.
O que mudou desde o SDK 8
Muitos exemplos ainda em linha usam a antiga API por namespaces. Deixou de funcionar assim desde o Firebase 9:
// SDK antigo (8 e anteriores) — já não funciona
import firebase from 'firebase'
const db = firebase.initializeApp(config).database()
db.ref('avis').push({ nom: 'Damien' })
// SDK modular (9 e seguintes)
import { initializeApp } from 'firebase/app'
import { addDoc, collection, getFirestore } from 'firebase/firestore'
const db = getFirestore(initializeApp(config))
await addDoc(collection(db, 'avis'), { nom: 'Damien' })O corte em funções importadas não é cosmético: permite ao bundler guardar apenas o que usas. Numa aplicação que se limita a ler o Firestore, a diferença de peso é evidente.
Do lado do VueFire, a antiga opção firebase: { … } nos componentes e o objeto $firebaseRefs desapareceram: tudo passa por useCollection e useDocument.
Para ir mais longe
Esta montagem dá por adquiridos os componentes e a reatividade do Vue. Se não for o caso, começa pelo tutorial de Vue 3 para principiantes. Para partilhar os dados do Firebase entre componentes distantes, um store Pinia que encapsule as chamadas ao Firestore é um bom padrão.
Erros frequentes
firebase.initializeApp(config).database() e o objeto global firebase deixaram de funcionar na versão 9. Tudo passa por funções importadas.firebase: { … } nos componentes e o $firebaseRefs desapareceram: usa o useCollection e o useDocument.

