Firebase con Vue 3: conectar Firestore paso a paso con VueFire

Firebase es una de las formas más sencillas de montar una base de datos alojada en tiempo real. VueFire lo pone todavía más fácil: ofrece un mapeo directo y las actualizaciones de los objetos de Firebase a través del sistema de reactividad de Vue. Juntos, el resultado es maravillosamente simple

Firebase con Vue 3: conectar Firestore paso a paso con VueFire
Respuesta rápida

Instala firebase y vuefire, inicializa la aplicación con initializeApp y getFirestore, y luego lee una colección con useCollection: la lista se actualiza sola. Desarrolla contra el emulador local de Firestore en lugar de hacerlo sobre el proyecto de producción.

Firebase aporta una base de datos, autenticación y alojamiento sin escribir un servidor. Enchufado a Vue, da una base en tiempo real cuyos cambios se propagan solos a la interfaz. Así se cablea correctamente con el SDK modular.

¿Firestore o Realtime Database?

Firebase ofrece dos bases. Realtime Database es la más antigua: un gran árbol JSON y consultas limitadas. Cloud Firestore organiza los datos en colecciones de documentos, admite consultas compuestas de verdad e índices. Para un proyecto nuevo, elige Firestore, es lo que hace este artículo.

Instalar

bash
npm install firebase vuefire

VueFire es la capa oficial que conecta Firebase con la reactividad de Vue. No es obligatoria, pero evita escribir a mano las suscripciones y su limpieza.

Inicializar

Crea el proyecto en la consola de Firebase, añade una aplicación web y copia la configuración. Guárdala en un archivo dedicado:

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 clave de API de Firebase es pública

Al contrario de lo que sugiere su nombre, no es un secreto: viaja en el bundle de JavaScript y cualquiera puede leerla. Identifica el proyecto, no lo autoriza. La seguridad descansa por completo en las reglas de Firestore y en la autenticación. Escribir esas reglas es la verdadera tarea de seguridad, no esconder la clave.

Después conecta VueFire a la aplicación:

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

Leer una colección

useCollection devuelve una referencia reactiva, que Firestore rellena y mantiene al día:

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>

Ya está: el bucle v-for muestra la colección como cualquier array. Abre la consola de Firebase y modifica un documento: la lista cambia en el navegador sin recargar. VueFire cierra la suscripción al desmontar el componente, lo que evita la fuga clásica de los listeners olvidados.

Para un documento suelto, useDocument sigue la misma lógica:

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

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

Filtrar y ordenar

Las consultas se componen con query, where, orderBy y 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 consulta que combina un filtro y una ordenación sobre campos distintos exige un índice compuesto. Firestore la rechaza y muestra en la consola un enlace que crea el índice de un clic, es el mensaje de error más útil del producto.

Escribir

Las escrituras pasan por las funciones del SDK, no por VueFire. Engánchalas a un formulario para crear documentos desde la interfaz:

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

// identificador generado por Firestore
await addDoc(collection(db, 'avis'), {
  nom: 'Damien',
  note: 5,
  creeLe: serverTimestamp()
})

// identificador elegido (crea o reemplaza)
await setDoc(doc(db, 'avis', 'avis-2234'), { nom: 'Damien', note: 5 })

// modificar algunos campos
await updateDoc(doc(db, 'avis', 'avis-2234'), { note: 4 })

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

serverTimestamp() deja que Firestore ponga la marca de tiempo en el servidor: la hora de la máquina del visitante no es fiable.

Desarrollar contra el emulador

Trabajar directamente sobre el proyecto de producción estropea los datos y consume cuota. La suite de emuladores de Firebase ejecuta Firestore en local.

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

Un identificador de proyecto que empieza por demo- le indica al emulador que funcione sin cuenta ni facturación.

En la aplicación, conecta el SDK al emulador solo en desarrollo:

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)
}
El emulador exige Java 21

Desde firebase-tools 15, una versión del JDK anterior a esa hace fallar el arranque con el mensaje «firebase-tools no longer supports Java version before 21». Compruébalo con java -version.

Las reglas de seguridad

Sin reglas, la base está cerrada o abierta a todo el mundo. El modo «prueba» que se propone al crearla caduca a los treinta días, no lo dejes en producción.

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

    match /avis/{avisId} {
      // lectura pública
      allow read: if true;

      // escritura reservada a quien haya iniciado sesión, y solo sobre su propia reseña
      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;
    }
  }
}

Las reglas también se escriben y se prueban contra el emulador, lo que evita descubrir un agujero en producción.

Lo que ha cambiado desde el SDK 8

Muchos ejemplos que siguen circulando usan la antigua API con espacios de nombres. Ya no funciona tal cual desde Firebase 9:

javascript
// SDK antiguo (8 y anteriores) — ya no funciona
import firebase from 'firebase'
const db = firebase.initializeApp(config).database()
db.ref('avis').push({ nom: 'Damien' })

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

El troceado en funciones importadas no es cosmético: permite que el bundler conserve solo lo que usas. En una aplicación que únicamente lee de Firestore, la diferencia de peso se nota.

Del lado de VueFire, la antigua opción firebase: { … } en los componentes y el objeto $firebaseRefs han desaparecido: todo pasa por useCollection y useDocument.

Para ir más lejos

Este montaje da por sabidos los componentes y la reactividad de Vue. Si no es tu caso, empieza por el tutorial de Vue 3 para principiantes. Para compartir los datos de Firebase entre componentes alejados, un store de Pinia que encapsule las llamadas a Firestore es un buen patrón.

Errores frecuentes

Seguir un tutorial escrito para el SDK 8 firebase.initializeApp(config).database() y el objeto global firebase ya no funcionan desde la versión 9. Todo pasa por funciones importadas.
Usar la antigua API de VueFire La opción firebase: { … } en los componentes y $firebaseRefs han desaparecido: usa useCollection y useDocument.
Creer que la clave de API es un secreto Viaja en el bundle y por sí sola no autoriza nada. La seguridad descansa en las reglas de Firestore.
Dejar las reglas en modo prueba Caducan a los treinta días y hasta entonces dejan la base abierta a escritura.
Emulador y versión de Java Desde firebase-tools 15, un JDK anterior a la versión 21 hace fallar el arranque.

FirebaseJavaScriptVue.js

Damien Flandrin Desarrollador web desde 2010, creador de Gekkode y de Email Impact. Cada artículo se prueba en un proyecto real antes de publicarse. Contacto
Newsletter

Las nuevas pruebas, tutoriales y proyectos, por correo.

Pruebas reproducibles, código versionado, resultados fechados. Nunca spam.