Tutorial Completo: Crear una Aplicación CRUD con Vue.js y Firebase
Aprende paso a paso cómo construir una aplicación CRUD (Crear, Leer, Actualizar, Eliminar) utilizando Vue.js para el frontend y Firebase como backend. Este tutorial está dirigido a desarrolladores principiantes e intermedios que desean iniciarse en el desarrollo web moderno, combinando un framework frontend progresivo con un servicio Backend-as-a-Service potente como Firebase.
Índice
- Introducción
- Requisitos Previos
- Paso 1: Configurar el Proyecto Vue.js
- Paso 2: Integrar Firebase Firestore para Almacenar Datos
- Paso 3: Implementar Funcionalidades CRUD
- Paso 4: Manejo de Estados y Eventos en Vue
- Paso 5: Autenticación Básica con Firebase Authentication
- Paso 6: Despliegue de la Aplicación
- Conclusión y Buenas Prácticas
Introducción
Las aplicaciones CRUD son la base de la mayoría de las aplicaciones web. En este tutorial aprenderás a construir una aplicación completa con Vue.js y Firebase, enfocándonos en el flujo de trabajo típico de desarrollo frontend con un backend en tiempo real y escalable.
Firebase ofrece varios servicios gestionados, entre ellos Firestore (base de datos NoSQL en tiempo real) y Authentication (gestión sencilla de usuarios), ideales para acelerar el desarrollo.
Nuestro objetivo será crear una app para gestionar una lista de tareas, donde los usuarios podrán iniciar sesión, crear, ver, actualizar y eliminar tareas.
Requisitos Previos
Antes de comenzar, asegúrate de tener:
- Conocimientos básicos de JavaScript y HTML.
- Node.js y npm instalados en tu sistema.
- Editor de código, como VSCode.
- Cuenta gratuita en Firebase.
Paso 1: Configurar el Proyecto Vue.js
Vamos a crear un proyecto nuevo usando Vue CLI, que nos facilita el setup inicial.
1.1 Instalar Vue CLI (si no lo tienes)
1 2 |
npm install -g @vue/cli |
1.2 Crear el proyecto
Ejecuta:
1 2 |
vue create crud-vue-firebase |
Selecciona opciones predeterminadas o personalizadas. Para principiantes, la configuración predeterminada está muy bien.
1.3 Entrar al directorio e iniciar la app
1 2 3 |
cd crud-vue-firebase npm run serve |
Abre http://localhost:8080 para ver tu proyecto funcionando.
Paso 2: Integrar Firebase Firestore para Almacenar Datos
Ahora, vamos a conectar nuestra app con Firebase para guardar y gestionar datos.
2.1 Crear un proyecto en Firebase
- Ingresa a https://console.firebase.google.com/
- Crea un nuevo proyecto, asigna un nombre.
- Activa Firestore Database en modo de prueba para facilitar el desarrollo.
- Habilita Authentication con Email y Contraseña.
2.2 Añadir Firebase a Vue.js
Dentro de tu proyecto Vue, instala el SDK de Firebase:
1 2 |
npm install firebase |
2.3 Configurar Firebase
En src
crea un archivo firebaseConfig.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// src/firebaseConfig.js import { initializeApp } from 'firebase/app'; import { getFirestore } from 'firebase/firestore'; import { getAuth } from 'firebase/auth'; const firebaseConfig = { apiKey: "TU_API_KEY", authDomain: "TU_AUTH_DOMAIN", projectId: "TU_PROJECT_ID", storageBucket: "TU_STORAGE_BUCKET", messagingSenderId: "TU_MESSAGING_SENDER_ID", appId: "TU_APP_ID" }; const app = initializeApp(firebaseConfig); const db = getFirestore(app); const auth = getAuth(app); export { db, auth }; |
Nota: Los valores los encuentras en la configuración de tu proyecto Firebase, en la sección “Configuración Web”.
Paso 3: Implementar Funcionalidades CRUD
3.1 Crear la estructura básica
En src/components
crea un componente TodoList.vue
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
<template> <div> <h2>Lista de Tareas</h2> <input v-model="newTask" @keyup.enter="addTask" placeholder="Nueva tarea..." /> <ul> <li v-for="task in tasks" :key="task.id"> <input type="checkbox" v-model="task.completed" @change="updateTask(task)" /> <span :style="{ textDecoration: task.completed ? 'line-through' : 'none' }">{{ task.name }}</span> <button @click="deleteTask(task.id)">Eliminar</button> </li> </ul> </div> </template> <script> import { ref, onMounted } from 'vue'; import { db } from '../firebaseConfig'; import { collection, addDoc, getDocs, updateDoc, deleteDoc, doc, onSnapshot } from 'firebase/firestore'; export default { setup() { const tasks = ref([]); const newTask = ref(''); const tasksCollection = collection(db, 'tasks'); // Leer datos en tiempo real onMounted(() => { onSnapshot(tasksCollection, (querySnapshot) => { tasks.value = []; querySnapshot.forEach((doc) => { tasks.value.push({ id: doc.id, ...doc.data() }); }); }); }); // Crear const addTask = async () => { if (newTask.value.trim() === '') return; await addDoc(tasksCollection, { name: newTask.value, completed: false }); newTask.value = ''; }; // Actualizar const updateTask = async (task) => { const taskDoc = doc(db, 'tasks', task.id); await updateDoc(taskDoc, { completed: task.completed }); }; // Eliminar const deleteTask = async (id) => { const taskDoc = doc(db, 'tasks', id); await deleteDoc(taskDoc); }; return { tasks, newTask, addTask, updateTask, deleteTask }; } }; </script> <style scoped> input[type="checkbox"] { margin-right: 8px; } button { margin-left: 12px; background-color: #ef4444; border: none; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer; } button:hover { background-color: #dc2626; } </style> |
3.2 Explicación:
- Usamos las funciones de Firestore para manejar la base de datos.
onSnapshot
permite actualizar en tiempo real la lista cuando cambien los datos.- Cada tarea posee un campo
completed
para marcar si está hecha. - Usamos
await
para asegurar que las operaciones asincrónicas se completen.
3.3 Importar y mostrar componente principal
En src/App.vue
, reemplaza el contenido con:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<template> <div id="app"> <h1>Aplicación CRUD Vue.js con Firebase</h1> <TodoList /> </div> </template> <script> import TodoList from './components/TodoList.vue'; export default { name: 'App', components: { TodoList } }; </script> <style> #app { max-width: 600px; margin: 40px auto; font-family: Arial, sans-serif; } </style> |
Paso 4: Manejo de Estados y Eventos en Vue
Ya vimos el básico manejo de estados con ref
y eventos con @click
, @change
, y @keyup.enter
.
4.1 ¿Por qué ref?
ref
crea un estado reactivo básico para variables escalares como strings o arrays.
4.2 Eventos importantes
@keyup.enter
nos permite agregar la tarea cuando se presiona Enter.@change
actualiza el estado de completado.@click
borra la tarea seleccionada.
Estas interacciones hacen que la app responda instantáneamente a la interacción del usuario.
Paso 5: Autenticación Básica con Firebase Authentication
Para que los usuarios puedan iniciar sesión y cada uno gestione sus tareas, agreguemos Authentication.
5.1 Crear formulario de login
Crea un componente nuevo Auth.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<template> <div> <h2>Login o Registro</h2> <input v-model="email" type="email" placeholder="Email" /> <input v-model="password" type="password" placeholder="Contraseña" /> <button @click="login">Ingresar</button> <button @click="register">Registrarse</button> <p v-if="errorMessage" style="color: red">{{ errorMessage }}</p> <p v-if="user">¡Hola, {{ user.email }}! <button @click="logout">Salir</button></p> </div> </template> <script> import { ref } from 'vue'; import { auth } from '../firebaseConfig'; import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, onAuthStateChanged } from 'firebase/auth'; export default { setup() { const email = ref(''); const password = ref(''); const errorMessage = ref(''); const user = ref(null); // Escuchar cambios de usuario onAuthStateChanged(auth, (u) => { user.value = u; }); const login = async () => { errorMessage.value = ''; try { await signInWithEmailAndPassword(auth, email.value, password.value); } catch (error) { errorMessage.value = error.message; } }; const register = async () => { errorMessage.value = ''; try { await createUserWithEmailAndPassword(auth, email.value, password.value); } catch (error) { errorMessage.value = error.message; } }; const logout = async () => { await signOut(auth); }; return { email, password, errorMessage, user, login, register, logout }; } }; </script> <style scoped> input { display: block; margin: 10px 0; padding: 8px; width: 300px; } button { margin-right: 10px; padding: 8px 12px; cursor: pointer; } </style> |
5.2 Integrar autenticación en la app
Modifica App.vue
para mostrar contenido según estado de usuario:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<template> <div id="app"> <h1>Aplicación CRUD Vue.js con Firebase</h1> <Auth v-if="!user" /> <TodoList v-else :userId="user.uid" /> </div> </template> <script> import { ref, onMounted } from 'vue'; import { auth } from './firebaseConfig'; import Auth from './components/Auth.vue'; import TodoList from './components/TodoList.vue'; import { onAuthStateChanged } from 'firebase/auth'; export default { name: 'App', components: { Auth, TodoList }, setup() { const user = ref(null); onMounted(() => { onAuthStateChanged(auth, (u) => { user.value = u; }); }); return { user }; } }; </script> <style> #app { max-width: 600px; margin: 40px auto; font-family: Arial, sans-serif; } </style> |
5.3 Limitar acceso a tareas por usuario
Modifica TodoList.vue
para filtrar tareas solo del usuario autenticado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// Añade una prop para recibir userId props: { userId: { type: String, required: true } }, // Cambia tasksCollection para filtrar por userId import { query, where } from 'firebase/firestore'; const tasksCollection = collection(db, 'tasks'); // En onMounted, usa query con filtro onMounted(() => { const q = query(tasksCollection, where('userId', '==', props.userId)); onSnapshot(q, (querySnapshot) => { tasks.value = []; querySnapshot.forEach((doc) => { tasks.value.push({ id: doc.id, ...doc.data() }); }); }); }); // En addTask, agrega userId await addDoc(tasksCollection, { name: newTask.value, completed: false, userId: props.userId }); |
Esto asegura que cada usuario solo vea y modifique sus propias tareas.
Paso 6: Despliegue de la Aplicación
6.1 Generar build de producción
1 2 |
npm run build |
El resultado estará en la carpeta dist
.
6.2 Desplegar con Firebase Hosting
Si aun no tienes Firebase CLI, instálalo:
1 2 |
npm install -g firebase-tools |
Luego inicia sesión y configura hosting:
1 2 3 |
firebase login firebase init hosting |
- Selecciona el proyecto Firebase que creaste.
- Usa
dist
como carpeta pública. - Elige “No” para configurar como SPA cuando pregunte (importante para Vue).
Finalmente sube tu app:
1 2 |
firebase deploy |
Obtendrás una URL pública para compartir tu aplicación.
Conclusión y Buenas Prácticas
En este tutorial “crear app Vue paso a paso” con Firebase, revisamos:
- Cómo configurar un proyecto Vue.js moderno.
- Integrar Firebase Firestore para una base de datos en tiempo real.
- Implementar operaciones CRUD básicas y gestión reactiva de estados.
- Añadir autenticación simple para usuarios.
- Desplegar la app en Firebase Hosting fácilmente.
Buenas Prácticas:
- Mantén tus claves API seguras y no las expongas en repositorios públicos.
- Usa reglas de seguridad en Firestore para proteger los datos.
- Separar componentes para mejor mantenimiento a medida que tu app crezca.
- Considera usar Vuex o Pinia para manejo avanzado de estados cuando sea necesario.
¡Ahora tienes una base sólida para continuar desarrollando con Vue.js y Firebase! Si quieres aprender más temas, suscríbete y sigue explorando.