Firebase y Astro
Firebase es una plataforma de desarrollo de aplicaciones que proporciona una base de datos NoSQL, autenticación, suscripciones en tiempo real, funciones y almacenamiento.
Consulta nuestra guía aparte para desplegar en el hosting de Firebase.
Inicializando Firebase en Astro
Sección titulada “Inicializando Firebase en Astro”Requisitos previos
Sección titulada “Requisitos previos”- Un proyecto de Firebase con una aplicación web configurada.
- Un proyecto de Astro con
output: 'server'habilitado para renderizado bajo demanda. - Firebase credentials: You will need two sets of credentials to connect Astro to Firebase:
- Credenciales de la aplicación web: Estas credenciales se usarán en el lado del cliente de tu aplicación. Puedes encontrarlas en la consola de Firebase en Configuración del proyecto > General. Desplázate hacia abajo hasta la sección Tus aplicaciones y haz clic en el icono de Aplicación web.
- Credenciales del proyecto: Estas credenciales se usarán en el lado del servidor de tu aplicación. Puedes generarlas en la consola de Firebase en Configuración del proyecto > Cuentas de servicio > SDK de Firebase Admin > Generar nueva clave privada.
Añadiendo credenciales de Firebase
Sección titulada “Añadiendo credenciales de Firebase”Para añadir tus credenciales de Firebase a Astro, crea un archivo .env en la raíz de tu proyecto con las siguientes variables:
FIREBASE_PRIVATE_KEY_ID=YOUR_PRIVATE_KEY_IDFIREBASE_PRIVATE_KEY=YOUR_PRIVATE_KEYFIREBASE_PROJECT_ID=YOUR_PROJECT_IDFIREBASE_CLIENT_EMAIL=YOUR_CLIENT_EMAILFIREBASE_CLIENT_ID=YOUR_CLIENT_IDFIREBASE_AUTH_URI=YOUR_AUTH_URIFIREBASE_TOKEN_URI=YOUR_TOKEN_URIFIREBASE_AUTH_CERT_URL=YOUR_AUTH_CERT_URLFIREBASE_CLIENT_CERT_URL=YOUR_CLIENT_CERT_URLAhora, estas variables de entorno están disponibles para su uso en tu proyecto.
Si deseas tener IntelliSense para tus variables de entorno de Firebase, edita o crea el archivo env.d.ts en tu directorio src/ y configura tus tipos:
interface ImportMetaEnv { readonly FIREBASE_PRIVATE_KEY_ID: string; readonly FIREBASE_PRIVATE_KEY: string; readonly FIREBASE_PROJECT_ID: string; readonly FIREBASE_CLIENT_EMAIL: string; readonly FIREBASE_CLIENT_ID: string; readonly FIREBASE_AUTH_URI: string; readonly FIREBASE_TOKEN_URI: string; readonly FIREBASE_AUTH_CERT_URL: string readonly FIREBASE_CLIENT_CERT_URL: string;}
interface ImportMeta { readonly env: ImportMetaEnv;}Lee más sobre variables de entorno y archivos .env en Astro.
Tu proyecto debería incluir ahora estos nuevos archivos:
Directoriosrc/
- env.d.ts
- .env
- astro.config.mjs
- package.json
Instalación de dependencias
Sección titulada "Instalación de dependencias"Para conectar Astro con Firebase, instala los siguientes paquetes usando el comando único a continuación para tu gestor de paquetes preferido:
firebase: el SDK de Firebase para el lado del clientefirebase-admin: el SDK de Firebase Admin para el lado del servidor
npm install firebase firebase-adminpnpm add firebase firebase-adminyarn add firebase firebase-adminA continuación, crea una carpeta llamada firebase en el directorio src/ y añade dos nuevos archivos a esta carpeta: client.ts y server.ts.
En client.ts, añade el siguiente código para inicializar Firebase en el cliente usando las credenciales de tu aplicación web y el paquete firebase:
import { initializeApp } from "firebase/app";
const firebaseConfig = { apiKey: "my-public-api-key", authDomain: "my-auth-domain", projectId: "my-project-id", storageBucket: "my-storage-bucket", messagingSenderId: "my-sender-id", appId: "my-app-id",};
export const app = initializeApp(firebaseConfig);Recuerda reemplazar el objeto firebaseConfig con las credenciales de tu propia aplicación web.
En server.ts, añade el siguiente código para inicializar Firebase en el servidor usando las credenciales de tu proyecto y el paquete firebase-admin:
import type { ServiceAccount } from "firebase-admin";import { initializeApp, cert, getApps } from "firebase-admin/app";
const activeApps = getApps();const serviceAccount = { type: "service_account", project_id: import.meta.env.FIREBASE_PROJECT_ID, private_key_id: import.meta.env.FIREBASE_PRIVATE_KEY_ID, private_key: import.meta.env.FIREBASE_PRIVATE_KEY, client_email: import.meta.env.FIREBASE_CLIENT_EMAIL, client_id: import.meta.env.FIREBASE_CLIENT_ID, auth_uri: import.meta.env.FIREBASE_AUTH_URI, token_uri: import.meta.env.FIREBASE_TOKEN_URI, auth_provider_x509_cert_url: import.meta.env.FIREBASE_AUTH_CERT_URL, client_x509_cert_url: import.meta.env.FIREBASE_CLIENT_CERT_URL,};
const initApp = () => { if (import.meta.env.PROD) { console.info('PROD env detected. Using default service account.') // Use default config in firebase functions. Should be already injected in the server by Firebase. return initializeApp() } console.info('Loading service account from env.') return initializeApp({ credential: cert(serviceAccount as ServiceAccount) })}
export const app = activeApps.length === 0 ? initApp() : activeApps[0];Recuerda reemplazar el objeto serviceAccount con las credenciales de tu propio proyecto.
Finalmente, tu proyecto debería incluir ahora estos nuevos archivos:
Directoriosrc
- env.d.ts
Directoriofirebase
- client.ts
- server.ts
- .env
- astro.config.mjs
- package.json
Añadiendo autenticación con Firebase
Sección titulada “Añadiendo autenticación con Firebase”Requisitos previos
Sección titulada “Requisitos previos”- Un proyecto de Astro inicializado con Firebase.
- Un proyecto de Firebase con autenticación de correo/contraseña habilitada en la consola de Firebase bajo Autenticación > Método de inicio de sesión.
Creando endpoints de servidor de autenticación
Sección titulada “Creando endpoints de servidor de autenticación”La autenticación de Firebase en Astro requiere los siguientes tres endpoints de servidor de Astro:
GET /api/auth/signin- para iniciar la sesión de un usuarioGET /api/auth/signout- para cerrar la sesión de un usuarioPOST /api/auth/register- para registrar a un usuario
Crea tres endpoints relacionados con la autenticación en un nuevo directorio src/pages/api/auth/: signin.ts, signout.ts y register.ts.
signin.ts contiene el código para iniciar la sesión de un usuario usando Firebase:
import type { APIRoute } from "astro";import { app } from "../../../firebase/server";import { getAuth } from "firebase-admin/auth";
export const GET: APIRoute = async ({ request, cookies, redirect }) => { const auth = getAuth(app);
/* Get token from request headers */ const idToken = request.headers.get("Authorization")?.split("Bearer ")[1]; if (!idToken) { return new Response( "No token found", { status: 401 } ); }
/* Verify id token */ try { await auth.verifyIdToken(idToken); } catch (error) { return new Response( "Invalid token", { status: 401 } ); }
/* Create and set session cookie */ const fiveDays = 60 * 60 * 24 * 5 * 1000; const sessionCookie = await auth.createSessionCookie(idToken, { expiresIn: fiveDays, });
cookies.set("__session", sessionCookie, { path: "/", });
return redirect("/dashboard");};Firebase solo permite el uso de una cookie, y debe llamarse __session. Cualquier otra cookie que envíe el cliente no será visible para tu aplicación.
Esta es una implementación básica del endpoint de inicio de sesión. Puedes añadir más lógica a este endpoint según tus necesidades.
signout.ts contiene el código para cerrar la sesión de un usuario eliminando la cookie de sesión:
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ redirect, cookies }) => { cookies.delete("__session", { path: "/", }); return redirect("/signin");};Esta es una implementación básica del endpoint de cierre de sesión. Puedes añadir más lógica a este endpoint según tus necesidades.
register.ts contiene el código para registrar a un usuario usando Firebase:
import type { APIRoute } from "astro";import { getAuth } from "firebase-admin/auth";import { app } from "../../../firebase/server";
export const POST: APIRoute = async ({ request, redirect }) => { const auth = getAuth(app);
/* Get form data */ const formData = await request.formData(); const email = formData.get("email")?.toString(); const password = formData.get("password")?.toString(); const name = formData.get("name")?.toString();
if (!email || !password || !name) { return new Response( "Missing form data", { status: 400 } ); }
/* Create user */ try { await auth.createUser({ email, password, displayName: name, }); } catch (error: any) { return new Response( "Something went wrong", { status: 400 } ); } return redirect("/signin");};Esta es una implementación básica del endpoint de registro. Puedes añadir más lógica a este endpoint según tus necesidades.
Después de crear los endpoints de servidor para la autenticación, el directorio de tu proyecto debería incluir ahora estos nuevos archivos:
Directoriosrc
- env.d.ts
Directoriofirebase
- client.ts
- server.ts
Directoriopages
Directorioapi
Directorioauth
- signin.ts
- signout.ts
- register.ts
- .env
- astro.config.mjs
- package.json
Creando páginas
Sección titulada “Creando páginas”Crea las páginas que usarán los endpoints de Firebase:
src/pages/register- contendrá un formulario para registrar a un usuariosrc/pages/signin- contendrá un formulario para iniciar la sesión de un usuariosrc/pages/dashboard- contendrá un panel de control al que solo pueden acceder los usuarios autenticados
El ejemplo de src/pages/register.astro a continuación incluye un formulario que enviará una solicitud POST al endpoint /api/auth/register. Este endpoint creará un nuevo usuario utilizando los datos del formulario y luego redirigirá al usuario a la página /signin.
---import Layout from "../layouts/Layout.astro";---
<Layout title="Register"> <h1>Register</h1> <p>Already have an account? <a href="/signin">Sign in</a></p> <form action="/api/auth/register" method="post"> <label for="name">Name</label> <input type="text" name="name" id="name" /> <label for="email" for="email">Email</label> <input type="email" name="email" id="email" /> <label for="password">Password</label> <input type="password" name="password" id="password" /> <button type="submit">Login</button> </form></Layout>src/pages/signin.astro utiliza la aplicación de servidor de Firebase para verificar la cookie de sesión del usuario. Si el usuario está autenticado, la página lo redirigirá a la página /dashboard.
La página de ejemplo a continuación contiene un formulario que enviará una solicitud POST al endpoint /api/auth/signin con el token de ID generado por la aplicación cliente de Firebase.
El endpoint verificará el token de ID y creará una nueva cookie de sesión para el usuario. Luego, el endpoint redirigirá al usuario a la página /dashboard.
---import { app } from "../firebase/server";import { getAuth } from "firebase-admin/auth";import Layout from "../layouts/Layout.astro";
/* Check if the user is authenticated */const auth = getAuth(app);if (Astro.cookies.has("__session")) { const sessionCookie = Astro.cookies.get("__session")!.value; const decodedCookie = await auth.verifySessionCookie(sessionCookie); if (decodedCookie) { return Astro.redirect("/dashboard"); }}---
<Layout title="Sign in"> <h1>Sign in</h1> <p>New here? <a href="/register">Create an account</a></p> <form action="/api/auth/signin" method="post"> <label for="email" for="email">Email</label> <input type="email" name="email" id="email" /> <label for="password">Password</label> <input type="password" name="password" id="password" /> <button type="submit">Login</button> </form></Layout><script> import { getAuth, inMemoryPersistence, signInWithEmailAndPassword, } from "firebase/auth"; import { app } from "../firebase/client";
const auth = getAuth(app); // This will prevent the browser from storing session data auth.setPersistence(inMemoryPersistence);
const form = document.querySelector("form") as HTMLFormElement; form.addEventListener("submit", async (e) => { e.preventDefault(); const formData = new FormData(form); const email = formData.get("email")?.toString(); const password = formData.get("password")?.toString();
if (!email || !password) { return; } const userCredential = await signInWithEmailAndPassword( auth, email, password ); const idToken = await userCredential.user.getIdToken(); const response = await fetch("/api/auth/signin", { method: "GET", headers: { Authorization: `Bearer ${idToken}`, }, });
if (response.redirected) { window.location.assign(response.url); } });</script>src/pages/dashboard.astro verificará la cookie de sesión del usuario utilizando la aplicación de servidor de Firebase. Si el usuario no está autenticado, la página lo redirigirá a la página /signin.
La página de ejemplo a continuación muestra el nombre del usuario y un botón para cerrar sesión. Al hacer clic en el botón, se enviará una solicitud GET al endpoint /api/auth/signout.
El endpoint eliminará la cookie de sesión del usuario y lo redirigirá a la página /signin.
---import { app } from "../firebase/server";import { getAuth } from "firebase-admin/auth";import Layout from "../layouts/Layout.astro";
const auth = getAuth(app);
/* Check current session */if (!Astro.cookies.has("__session")) { return Astro.redirect("/signin");}const sessionCookie = Astro.cookies.get("__session")!.value;const decodedCookie = await auth.verifySessionCookie(sessionCookie);const user = await auth.getUser(decodedCookie.uid);
if (!user) { return Astro.redirect("/signin");}---
<Layout title="dashboard"> <h1>Welcome {user.displayName}</h1> <p>We are happy to see you here</p> <form action="/api/auth/signout"> <button type="submit">Sign out</button> </form></Layout>Añadiendo proveedores de OAuth
Sección titulada “Añadiendo proveedores de OAuth”Para añadir proveedores de OAuth a tu aplicación, debes habilitarlos en la consola de Firebase.
En la consola de Firebase, ve a la sección Autenticación y haz clic en la pestaña Método de inicio de sesión. Luego, haz clic en el botón Añadir nuevo proveedor y habilita los proveedores que quieras usar.
El ejemplo a continuación utiliza el proveedor de Google.
Edita la página signin.astro para añadir:
- un botón para iniciar sesión con Google debajo del formulario existente
- un detector de eventos en el botón para manejar el proceso de inicio de sesión en la etiqueta
<script>existente.
---import { app } from "../firebase/server";import { getAuth } from "firebase-admin/auth";import Layout from "../layouts/Layout.astro";
/* Check if the user is authenticated */const auth = getAuth(app);if (Astro.cookies.has("__session")) { const sessionCookie = Astro.cookies.get("__session")!.value; const decodedCookie = await auth.verifySessionCookie(sessionCookie); if (decodedCookie) { return Astro.redirect("/dashboard"); }}---
<Layout title="Sign in"> <h1>Sign in</h1> <p>New here? <a href="/register">Create an account</a></p> <form action="/api/auth/signin" method="post"> <label for="email" for="email">Email</label> <input type="email" name="email" id="email" /> <label for="password">Password</label> <input type="password" name="password" id="password" /> <button type="submit">Login</button> </form> <button id="google">Sign in with Google</button></Layout><script> import { getAuth, inMemoryPersistence, signInWithEmailAndPassword, GoogleAuthProvider, signInWithPopup, } from "firebase/auth"; import { app } from "../firebase/client";
const auth = getAuth(app); auth.setPersistence(inMemoryPersistence);
const form = document.querySelector("form") as HTMLFormElement; form.addEventListener("submit", async (e) => { e.preventDefault(); const formData = new FormData(form); const email = formData.get("email")?.toString(); const password = formData.get("password")?.toString();
if (!email || !password) { return; } const userCredential = await signInWithEmailAndPassword( auth, email, password ); const idToken = await userCredential.user.getIdToken(); const response = await fetch("/api/auth/signin", { headers: { Authorization: `Bearer ${idToken}`, }, });
if (response.redirected) { window.location.assign(response.url); } });
const googleSignin = document.querySelector("#google") as HTMLButtonElement; googleSignin.addEventListener("click", async () => { const provider = new GoogleAuthProvider(); const userCredential = await signInWithPopup(auth, provider); const idToken = await userCredential.user.getIdToken(); const res = await fetch("/api/auth/signin", { headers: { Authorization: `Bearer ${idToken}`, }, });
if (res.redirected) { window.location.assign(res.url); } });</script>Cuando se haga clic, el botón de inicio de sesión de Google abrirá una ventana emergente para iniciar sesión con Google. Una vez que el usuario inicie sesión, enviará una solicitud POST al endpoint /api/auth/signin con el token de ID generado por el proveedor de OAuth.
El endpoint verificará el token de ID y creará una nueva cookie de sesión para el usuario. Luego, el endpoint redirigirá al usuario a la página /dashboard.
Conectando a la base de datos Firestore
Sección titulada “Conectando a la base de datos Firestore”Requisitos previos
Sección titulada “Requisitos previos”-
Un proyecto de Astro inicializado con Firebase como se describe en la sección Inicializando Firebase en Astro.
-
Un proyecto de Firebase con una base de datos Firestore. Puedes seguir la documentación de Firebase para crear un nuevo proyecto y configurar una base de datos Firestore.
En esta receta, la colección de Firestore se llamará friends y contendrá documentos con los siguientes campos:
id: autogenerado por Firestorename: un campo de texto (string)age: un campo numérico (number)isBestFriend: un campo booleano (boolean)
Creando los endpoints de servidor
Sección titulada “Creando los endpoints de servidor”Crea dos nuevos archivos en un nuevo directorio src/pages/api/friends/: index.ts y [id].ts. Estos crearán dos endpoints de servidor para interactuar con la base de datos Firestore de las siguientes maneras:
POST /api/friends: para crear un nuevo documento en la colección friends.POST /api/friends/:id: para actualizar un documento en la colección friends.DELETE /api/friends/:id: para eliminar un documento en la colección friends.
index.ts contendrá el código para crear un nuevo documento en la colección friends:
import type { APIRoute } from "astro";import { app } from "../../../firebase/server";import { getFirestore } from "firebase-admin/firestore";
export const POST: APIRoute = async ({ request, redirect }) => { const formData = await request.formData(); const name = formData.get("name")?.toString(); const age = formData.get("age")?.toString(); const isBestFriend = formData.get("isBestFriend") === "on";
if (!name || !age) { return new Response("Missing required fields", { status: 400, }); } try { const db = getFirestore(app); const friendsRef = db.collection("friends"); await friendsRef.add({ name, age: parseInt(age), isBestFriend, }); } catch (error) { return new Response("Something went wrong", { status: 500, }); } return redirect("/dashboard");};Esta es una implementación básica del endpoint friends. Puedes añadir más lógica a este endpoint según tus necesidades.
[id].ts contendrá el código para actualizar y eliminar un documento en la colección friends:
import type { APIRoute } from "astro";import { app } from "../../../firebase/server";import { getFirestore } from "firebase-admin/firestore";
const db = getFirestore(app);const friendsRef = db.collection("friends");
export const POST: APIRoute = async ({ params, redirect, request }) => { const formData = await request.formData(); const name = formData.get("name")?.toString(); const age = formData.get("age")?.toString(); const isBestFriend = formData.get("isBestFriend") === "on";
if (!name || !age) { return new Response("Missing required fields", { status: 400, }); }
if (!params.id) { return new Response("Cannot find friend", { status: 404, }); }
try { await friendsRef.doc(params.id).update({ name, age: parseInt(age), isBestFriend, }); } catch (error) { return new Response("Something went wrong", { status: 500, }); } return redirect("/dashboard");};
export const DELETE: APIRoute = async ({ params, redirect }) => { if (!params.id) { return new Response("Cannot find friend", { status: 404, }); }
try { await friendsRef.doc(params.id).delete(); } catch (error) { return new Response("Something went wrong", { status: 500, }); } return redirect("/dashboard");};Esta es una implementación básica del endpoint friends/:id. Puedes añadir más lógica a este endpoint según tus necesidades.
Después de crear los endpoints de servidor para Firestore, el directorio de tu proyecto debería incluir ahora estos nuevos archivos:
Directoriosrc
- env.d.ts
Directoriofirebase
- client.ts
- server.ts
Directoriopages
Directorioapi
Directoriofriends
- index.ts
- [id].ts
- .env
- astro.config.mjs
- package.json
Creando páginas
Sección titulada “Creando páginas”Crea las páginas que usarán los endpoints de Firestore:
src/pages/add.astro- contendrá un formulario para añadir un nuevo amigo.src/pages/edit/[id].astro- contendrá un formulario para editar un amigo y un botón para eliminar un amigo.src/pages/friend/[id].astro- contendrá los detalles de un amigo.src/pages/dashboard.astro- mostrará una lista de amigos.
Añadir un nuevo registro
Sección titulada “Añadir un nuevo registro”El ejemplo de src/pages/add.astro a continuación incluye un formulario que enviará una solicitud POST al endpoint /api/friends. Este endpoint creará un nuevo amigo utilizando los datos del formulario y luego redirigirá al usuario a la página /dashboard.
---import Layout from "../layouts/Layout.astro";---
<Layout title="Add a new friend"> <h1>Add a new friend</h1> <form method="post" action="/api/friends"> <label for="name">Name</label> <input type="text" id="name" name="name" /> <label for="age">Age</label> <input type="number" id="age" name="age" /> <label for="isBestFriend">Is best friend?</label> <input type="checkbox" id="isBestFriend" name="isBestFriend" /> <button type="submit">Add friend</button> </form></Layout>Editar o eliminar un registro
Sección titulada “Editar o eliminar un registro”src/pages/edit/[id].astro contendrá un formulario para editar los datos de un amigo y un botón para eliminar un amigo. Al enviar el formulario, esta página enviará una solicitud POST al endpoint /api/friends/:id para actualizar los datos del amigo.
Si el usuario hace clic en el botón de eliminar, esta página enviará una solicitud DELETE al endpoint /api/friends/:id para eliminar al amigo.
---import Layout from "../../layouts/Layout.astro";import { app } from "../../firebase/server";import { getFirestore } from "firebase-admin/firestore";
interface Friend { name: string; age: number; isBestFriend: boolean;}
const { id } = Astro.params;
if (!id) { return Astro.redirect("/404");}
const db = getFirestore(app);const friendsRef = db.collection("friends");const friendSnapshot = await friendsRef.doc(id).get();
if (!friendSnapshot.exists) { return Astro.redirect("/404");}
const friend = friendSnapshot.data() as Friend;---
<Layout title="Edit {friend.name}"> <h1>Edit {friend.name}</h1> <p>Here you can edit or delete your friend's data.</p> <form method="post" action={`/api/friends/${id}`}> <label for="name">Name</label> <input type="text" id="name" name="name" value={friend.name} /> <label for="age">Age</label> <input type="number" id="age" name="age" value={friend.age} /> <label for="isBestFriend">Is best friend?</label> <input type="checkbox" id="isBestFriend" name="isBestFriend" checked={friend.isBestFriend} /> <button type="submit">Edit friend</button> </form> <button type="button" id="delete-document">Delete</button></Layout><script> const deleteButton = document.getElementById( "delete-document" ) as HTMLButtonElement; const url = document.querySelector("form")?.getAttribute("action") as string; deleteButton.addEventListener("click", async () => { const response = await fetch(url, { method: "DELETE", }); if (response.redirected) { window.location.assign(response.url); } });</script>Mostrar un registro individual
Sección titulada “Mostrar un registro individual”src/pages/friend/[id].astro mostrará los detalles de un amigo.
---import Layout from "../../layouts/Layout.astro";import { app } from "../../firebase/server";import { getFirestore } from "firebase-admin/firestore";
interface Friend { name: string; age: number; isBestFriend: boolean;}
const { id } = Astro.params;
if (!id) { return Astro.redirect("/404");}
const db = getFirestore(app);const friendsRef = db.collection("friends");const friendSnapshot = await friendsRef.doc(id).get();
if (!friendSnapshot.exists) { return Astro.redirect("/404");}
const friend = friendSnapshot.data() as Friend;---
<Layout title={friend.name}> <h1>{friend.name}</h1> <p>Age: {friend.age}</p> <p>Is best friend: {friend.isBestFriend ? "Yes" : "No"}</p></Layout>Mostrar una lista de registros con un botón de editar
Sección titulada “Mostrar una lista de registros con un botón de editar”Finalmente, src/pages/dashboard.astro mostrará una lista de amigos. Cada amigo tendrá un enlace a su página de detalles y un botón de editar que redirigirá al usuario a la página de edición.
---import { app } from "../firebase/server";import { getFirestore } from "firebase-admin/firestore";import Layout from "../layouts/Layout.astro";
interface Friend { id: string; name: string; age: number; isBestFriend: boolean;}
const db = getFirestore(app);const friendsRef = db.collection("friends");const friendsSnapshot = await friendsRef.get();const friends = friendsSnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(),})) as Friend[];---
<Layout title="My friends"> <h1>Friends</h1> <ul> { friends.map((friend) => ( <li> <a href={`/friend/${friend.id}`}>{friend.name}</a> <span>({friend.age})</span> <strong>{friend.isBestFriend ? "Bestie" : "Friend"}</strong> <a href={`/edit/${friend.id}`}>Edit</a> </li> )) } </ul></Layout>Después de crear todas las páginas, deberías tener la siguiente estructura de archivos:
Directoriosrc
- env.d.ts
Directoriofirebase
- client.ts
- server.ts
Directoriopages
- dashboard.astro
- add.astro
Directorioedit
- [id].astro
Directoriofriend
- [id].astro
Directorioapi
Directoriofriends
- index.ts
- [id].ts
- .env
- astro.config.mjs
- package.json
Recursos de la comunidad
Sección titulada "Recursos de la comunidad"- Ejemplo de aplicación SSR con Astro y Firebase
- Uso de Firebase Realtime Database en Astro con Vue: una guía paso a paso