Estructura del Proyecto Astro
Aprende cómo se organiza un proyecto Astro y qué función cumple cada carpeta y archivo.
1. Vista General del Proyecto
Cuando creas un proyecto Astro con npm create astro@latest, obtienes una estructura organizada y clara.
2. src/pages/ - Sistema de Rutas
pages/ es la carpeta más importante. Cada archivo .astro aquí se convierte automáticamente en una ruta.
Routing basado en archivos: El nombre del archivo determina la URL.
Archivo:
src/pages/index.astro Ruta:
https://tusitio.com/ Archivo:
src/pages/blog.astro Ruta:
https://tusitio.com/blog Archivo:
src/pages/blog/post-1.astro Ruta:
https://tusitio.com/blog/post-1 Archivo:
src/pages/productos/[id].astro Ruta:
https://tusitio.com/productos/123 Ruta dinámica con parámetro
Ejemplo: src/pages/blog.astro
1---2// Código de la página (se ejecuta en el servidor)3const titulo = "Mi Blog";4const posts = [5 { id: 1, titulo: "Primer Post" },6 { id: 2, titulo: "Segundo Post" }7];8---9 10<!DOCTYPE html>11<html lang="es">12<head>13 <meta charset="UTF-8">14 <title>{titulo}</title>15</head>16<body>17 <h1>{titulo}</h1>18 <ul>19 {posts.map(post => (20 <li><a href={`/blog/${post.id}`}>{post.titulo}</a></li>21 ))}22 </ul>23</body>24</html> 3. src/layouts/ - Plantillas Reutilizables
Los layouts son plantillas que envuelven el contenido de tus páginas. Perfectos para headers, footers y estructura común.
DRY (Don't Repeat Yourself): Define una vez, usa en todas las páginas.
src/layouts/Base.astro
1---2const { titulo } = Astro.props;3---4 5<!DOCTYPE html>6<html lang="es">7<head>8 <meta charset="UTF-8">9 <title>{titulo}</title>10</head>11<body>12 <header>13 <nav>Mi Sitio</nav>14 </header>15 16 <main>17 <slot />18 </main>19 20 <footer>21 © 202522 </footer>23</body>24</html>src/pages/about.astro
1---2import Base from '../layouts/Base.astro';3---4 5<Base titulo="Sobre Nosotros">6 <h1>Acerca de</h1>7 <p>Esta es la página sobre nosotros.</p>8</Base> Tip: El <slot /> es donde se inserta el contenido de la página que usa el layout.
Cómo funciona el flujo Layout + Página
src/layouts/Base.astro
src/pages/index.astro
HTML resultante en el navegador
Flujo Visual:
Layout
Estructura común
Página
Contenido único
HTML Final
Página completa
Reutilizando el mismo Layout en múltiples páginas
src/pages/index.astro
1---2import Base from '../layouts/Base.astro';3---4 5<Base titulo="Inicio">6 <h1>Inicio</h1>7 <p>Página principal</p>8</Base>Ruta: /
src/pages/blog.astro
1---2import Base from '../layouts/Base.astro';3---4 5<Base titulo="Blog">6 <h1>Blog</h1>7 <p>Artículos recientes</p>8</Base>Ruta: /blog
src/pages/contact.astro
1---2import Base from '../layouts/Base.astro';3---4 5<Base titulo="Contacto">6 <h1>Contacto</h1>7 <form>...</form>8</Base>Ruta: /contact
src/pages/about.astro
1---2import Base from '../layouts/Base.astro';3---4 5<Base titulo="Nosotros">6 <h1>Sobre Nosotros</h1>7 <p>Nuestra historia</p>8</Base>Ruta: /about
Ventaja: Las 4 páginas comparten el mismo header, footer y estructura. Si cambias el Layout, ¡cambian todas las páginas automáticamente!
4. src/components/ - Componentes UI
Los components son piezas reutilizables de UI. Pueden ser componentes Astro (.astro) o de frameworks (React, Vue, Svelte).
Ejemplo: src/components/Card.astro
1---2const { titulo, descripcion } = Astro.props;3---4 5<div class="card">6 <h3>{titulo}</h3>7 <p>{descripcion}</p>8</div>9 10<style>11 .card {12 border: 1px solid #ccc;13 border-radius: 8px;14 padding: 1rem;15 background: white;16 }17</style>Usando el componente:
1---2import Card from '../components/Card.astro';3---4 5<Card6 titulo="Astro es genial"7 descripcion="Aprende Astro fácilmente"8/>9<Card10 titulo="Componentes reutilizables"11 descripcion="Escribe una vez, usa muchas veces"12/> 5. public/ - Archivos Estáticos
La carpeta public/ contiene archivos que se sirven directamente sin procesamiento: imágenes, fuentes, favicon, robots.txt, etc.
Importante: Los archivos en public/ se copian tal cual al build final.
Cómo referenciar archivos de public/:
1<!-- Imagen en public/logo.png -->2<img src="/logo.png" alt="Logo" />3 4<!-- Imagen en public/images/hero.jpg -->5<img src="/images/hero.jpg" alt="Hero" />6 7<!-- Favicon en public/favicon.svg -->8<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> Nota: Las rutas empiezan con / porque se sirven desde la raíz del sitio.
6. Buenas Prácticas
Usa layouts para estructura común
Crea layouts para headers, footers y estructura repetida. Evita duplicar código.
Componentes pequeños y reutilizables
Divide tu UI en componentes pequeños. Es más fácil mantener y reutilizar.
Organiza pages/ por funcionalidad
Usa subcarpetas en pages/ para agrupar rutas relacionadas: blog/, productos/, etc.
Imágenes optimizadas en public/
Usa formatos modernos (WebP, AVIF) y comprime imágenes antes de subirlas a public/.
Nombres descriptivos en inglés
Usa nombres claros para archivos y componentes: ProductCard.astro en vez de comp1.astro.
6.1. ¿Cómo funcionan las Props?
Las props (propiedades) son la forma de pasar datos a un componente o layout. Es como llamar a una función y pasarle parámetros.
Piensa en las props como variables que recibes desde fuera del componente.
1. Definir qué props acepta
En el componente/layout, usas Astro.props para recibir:
1---2// Card.astro3const { titulo, descripcion } = Astro.props;4---5 6<div class="card">7 <h3>{titulo}</h3>8 <p>{descripcion}</p>9</div>2. Pasar props al usarlo
Cuando usas el componente, le pasas valores:
1---2import Card from '../components/Card.astro';3---4 5<Card6 titulo="Mi Card"7 descripcion="Esto es una descripción"8/>Flujo de las Props:
Página usa componente
<Card titulo="Hola" /> Componente recibe props
const { titulo } = Astro.props Componente usa props
<h3>{titulo}</h3> Analogía: Las props son como los ingredientes de una receta. Tú decides qué ingredientes (props) pasas, y el componente los usa para "cocinar" el HTML final.
6.2. ¿Cómo funcionan los Slots?
Los slots son "huecos" donde puedes insertar contenido HTML completo. Es como un espacio reservado que se rellena con lo que le pases.
Piensa en los slots como cajones vacíos que se llenan con el contenido que tú decidas.
Ejemplo 1: Slot básico (sin nombre)
<slot /> 📁 Archivo:
src/components/Card.astro 1---2// Card.astro - Componente reutilizable3---4 5<div class="card">6 <h3>Mi Card</h3>7 8 <slot />9 <!--10 ↑ Este <slot /> es un HUECO11 Lo que pongas entre <Card> y </Card>12 aparecerá aquí13 -->14</div><Card> y </Card> irá al slot 📁 Archivo:
src/pages/index.astro 1---2import Card from '../components/Card.astro';3---4 5<Card>6 <!-- ⬇️ TODO ESTO va al <slot /> del componente -->7 <p>Este texto va al slot</p>8 <button>Click aquí</button>9 <!-- ⬆️ Esto reemplaza el <slot /> -->10</Card>11 12<!--13 CLAVE: No es una etiqueta HTML normal.14 <Card> es un COMPONENTE que tiene un <slot />15 El contenido entre <Card> y </Card> se inserta en ese slot16--><slot /> fue reemplazado por el contenido: 1<div class="card">2 <h3>Mi Card</h3>3 4 <!-- El <slot /> fue reemplazado por: -->5 <p>Este texto va al slot</p>6 <button>Click aquí</button>7</div>Ejemplo 2: Slots con nombre (múltiples huecos)
📁 Archivo:
src/layouts/MainLayout.astro 1---2// MainLayout.astro3---4 5<html>6 <body>7 <main>8 <slot />9 <!--10 ↑ HUECO 1: Sin nombre11 Aquí va el contenido "normal"12 -->13 </main>14 15 <aside>16 <slot name="sidebar" />17 <!--18 ↑ HUECO 2: Con nombre "sidebar"19 Aquí va SOLO el contenido con slot="sidebar"20 -->21 </aside>22 </body>23</html>slot="nombre" 📁 Archivo:
src/pages/blog.astro 1---2import MainLayout from '../layouts/MainLayout.astro';3---4 5<MainLayout>6 <!-- ⬇️ SIN slot="" = va al <slot /> sin nombre -->7 <h1>Mi Blog</h1>8 <p>Contenido principal</p>9 <!-- ⬆️ Esto va al <main> -->10 11 <!-- ⬇️ CON slot="sidebar" = va al <slot name="sidebar" /> -->12 <div slot="sidebar">13 <h3>Categorías</h3>14 <ul>15 <li>JavaScript</li>16 <li>Astro</li>17 </ul>18 </div>19 <!-- ⬆️ Esto va al <aside> -->20</MainLayout>21 22<!--23 CLAVE:24 - Sin slot="" → va al slot sin nombre25 - Con slot="sidebar" → va al slot llamado "sidebar"26-->1<html>2 <body>3 <main>4 <!-- El <slot /> sin nombre fue reemplazado por: -->5 <h1>Mi Blog</h1>6 <p>Contenido principal</p>7 </main>8 9 <aside>10 <!-- El <slot name="sidebar" /> fue reemplazado por: -->11 <div>12 <h3>Categorías</h3>13 <ul>14 <li>JavaScript</li>15 <li>Astro</li>16 </ul>17 </div>18 </aside>19 </body>20</html>Ejemplo 3: Insertar componentes dentro del slot
¿Qué hace especial a los slots? Puedes insertar cualquier cosa: HTML básico, otros componentes, o una mezcla de ambos. Esto se llama composición de componentes.
📁 Archivo:
src/components/Button.astro 1---2// Button.astro - Componente de botón reutilizable3const { texto, color = 'blue' } = Astro.props;4---5 6<button class={`btn btn-${color}`}>7 {texto}8</button>📁 Archivo:
src/components/Card.astro 1---2// Card.astro3const { titulo } = Astro.props;4---5 6<div class="card">7 <h3>{titulo}</h3>8 9 <slot />10 <!--11 ↑ Este slot puede recibir:12 - HTML normal: <p>, <div>, etc.13 - Otros componentes: <Button />, <Image />, etc.14 - O una mezcla de ambos!15 -->16</div>📁 Archivo:
src/pages/index.astro 1---2import Card from '../components/Card.astro';3import Button from '../components/Button.astro';4---5 6<Card titulo="Mi Tarjeta">7 <!-- ⬇️ Dentro del slot: HTML + Componentes -->8 9 <p>Este es el contenido de la tarjeta</p>10 11 <!-- Insertas un componente Button con props -->12 <Button texto="Click aquí" color="green" />13 <Button texto="Cancelar" color="red" />14 15 <!-- ⬆️ Todo esto va al <slot /> de Card -->16</Card>17 18<!--19 CLAVE - Composición:20 - Card recibe la prop "titulo"21 - Dentro del slot de Card insertas:22 * HTML normal (<p>)23 * Componentes Button con sus propias props24 25 Esto es MUY potente: combinas componentes reutilizables26-->1<div class="card">2 <h3>Mi Tarjeta</h3>3 4 <!-- El slot fue reemplazado por: -->5 <p>Este es el contenido de la tarjeta</p>6 7 <!-- Los componentes Button se renderizaron: -->8 <button class="btn btn-green">9 Click aquí10 </button>11 <button class="btn btn-red">12 Cancelar13 </button>14</div>15 16<!--17 ✨ Resultado:18 1. Card usó su prop "titulo" → <h3>Mi Tarjeta</h3>19 2. El <slot /> se reemplazó por todo el contenido20 3. Los componentes Button usaron sus props (texto y color)21-->🎯 Ventaja de combinar Props + Slots
✓ Props:
Para datos simples y configuración
titulo="Mi Tarjeta" ✓ Slots:
Para contenido complejo y flexible
<Card>contenido complejo</Card> Composición = Puedes anidar componentes dentro de otros. Card no necesita saber qué contiene (puede ser Button, Image, Video, etc.). Los slots lo hacen flexible y reutilizable.
Regla para recordar:
Slot sin nombre:
<slot /> El contenido que NO tiene atributo slot="" va aquí
<Card>contenido</Card> Slot con nombre:
<slot name="sidebar" /> Solo va el contenido que tenga slot="sidebar"
<div slot="sidebar">...</div> Analogía del slot: Cuando usas <Card>contenido</Card>, NO es una etiqueta HTML como <div>. Es un componente que tiene un hueco (<slot />) donde se inserta tu contenido.
Props vs Slots - ¿Cuándo usar cada uno?
Usa Props para:
- • Datos simples: texto, números, booleanos
- • Configuración: titulo, color, tamaño
- • Ejemplo:
titulo="Hola"
Usa Slots para:
- • HTML complejo: párrafos, listas, imágenes
- • Contenido variable: el contenido principal de una página
- • Ejemplo:
<slot />
Regla simple: Si es un texto corto → Props. Si es HTML completo → Slot.
7. Ejercicios Prácticos
Pon a prueba lo que has aprendido con estos ejercicios. Intenta resolverlos por tu cuenta antes de ver la solución.
Layout con Navegación y Páginas
Enunciado:
Crea un layout llamado MainLayout.astro en src/layouts/ que tenga:
- • Props:
titulo(para el <title>) ydescripcion(para meta description) - • Un
<header>con "Mi Sitio Web" y navegación con enlaces: Inicio (/), Blog (/blog), Contacto (/contacto) - • Enlaces resaltados cuando estés en esa página (usa
Astro.url.pathname) - • Layout de 2 columnas:
<main>con slot principal +<aside>con slotsidebar - • Un
<footer>con "© 2025 - Mi Sitio"
Luego, crea 3 páginas en src/pages/:
- 1.
index.astro- Página de inicio con contenido principal y sidebar - 2.
blog.astro- Página de blog con lista de artículos y sidebar - 3.
contacto.astro- Página de contacto con formulario y sidebar
Objetivo: Todas las páginas deben usar el mismo layout. Al navegar, el enlace activo debe cambiar. Los estilos CSS son opcionales - céntrate en entender Astro.
Ver Solución
src/layouts/MainLayout.astro
1---2const { titulo, descripcion } = Astro.props;3const rutaActual = Astro.url.pathname;4---5 6<!DOCTYPE html>7<html lang="es">8<head>9 <meta charset="UTF-8">10 <meta name="viewport" content="width=device-width, initial-scale=1.0">11 <meta name="description" content={descripcion}>12 <title>{titulo}</title>13</head>14<body>15 <header>16 <h1>Mi Sitio Web</h1>17 <nav>18 <a href="/" class={rutaActual === '/' ? 'active' : ''}>Inicio</a>19 <a href="/blog" class={rutaActual === '/blog' ? 'active' : ''}>Blog</a>20 <a href="/contacto" class={rutaActual === '/contacto' ? 'active' : ''}>Contacto</a>21 </nav>22 </header>23 24 <div class="container">25 <main>26 <slot />27 </main>28 29 <aside>30 <slot name="sidebar" />31 </aside>32 </div>33 34 <footer>35 <p>© 2025 - Mi Sitio</p>36 </footer>37</body>38</html>39 40<style>41 /* Estilos mínimos - personalízalos como quieras */42 .container {43 display: grid;44 grid-template-columns: 1fr 300px;45 gap: 2rem;46 }47 48 nav a.active {49 font-weight: bold;50 }51</style>src/pages/index.astro
1---2import MainLayout from '../layouts/MainLayout.astro';3---4 5<MainLayout6 titulo="Inicio - Mi Sitio Web"7 descripcion="Bienvenido a mi sitio web personal"8>9 <h2>Bienvenido a mi sitio</h2>10 <p>Esta es la página de inicio con contenido principal.</p>11 <p>Navega por las diferentes secciones usando el menú superior.</p>12 13 <div slot="sidebar">14 <h3>Sobre mí</h3>15 <p>Desarrollador web aprendiendo Astro.</p>16 <h4>Enlaces rápidos</h4>17 <ul>18 <li><a href="/blog">Ver Blog</a></li>19 <li><a href="/contacto">Contactar</a></li>20 </ul>21 </div>22</MainLayout>src/pages/blog.astro
1---2import MainLayout from '../layouts/MainLayout.astro';3 4const articulos = [5 { id: 1, titulo: 'Mi primer artículo', fecha: '2025-01-15' },6 { id: 2, titulo: 'Aprendiendo Astro', fecha: '2025-01-20' },7 { id: 3, titulo: 'Layouts y componentes', fecha: '2025-01-25' }8];9---10 11<MainLayout12 titulo="Blog - Mi Sitio Web"13 descripcion="Lee mis últimos artículos sobre desarrollo web"14>15 <h2>Blog</h2>16 <p>Bienvenido a mi blog. Aquí publico artículos sobre desarrollo web.</p>17 18 {articulos.map(articulo => (19 <article>20 <h3>{articulo.titulo}</h3>21 <p><small>{articulo.fecha}</small></p>22 <p>Resumen del artículo...</p>23 </article>24 ))}25 26 <div slot="sidebar">27 <h3>Categorías</h3>28 <ul>29 <li>JavaScript</li>30 <li>Astro</li>31 <li>CSS</li>32 </ul>33 <h3>Archivos</h3>34 <ul>35 <li>Enero 2025</li>36 <li>Diciembre 2024</li>37 </ul>38 </div>39</MainLayout>src/pages/contacto.astro
1---2import MainLayout from '../layouts/MainLayout.astro';3---4 5<MainLayout6 titulo="Contacto - Mi Sitio Web"7 descripcion="Ponte en contacto conmigo"8>9 <h2>Contacto</h2>10 <p>¿Tienes alguna pregunta? Envíame un mensaje.</p>11 12 <form>13 <div>14 <label for="nombre">Nombre:</label>15 <input type="text" id="nombre" name="nombre" required>16 </div>17 18 <div>19 <label for="email">Email:</label>20 <input type="email" id="email" name="email" required>21 </div>22 23 <div>24 <label for="mensaje">Mensaje:</label>25 <textarea id="mensaje" name="mensaje" rows="5" required></textarea>26 </div>27 28 <button type="submit">Enviar</button>29 </form>30 31 <div slot="sidebar">32 <h3>Info de contacto</h3>33 <ul>34 <li><strong>Email:</strong> info@example.com</li>35 <li><strong>Twitter:</strong> @miusuario</li>36 <li><strong>GitHub:</strong> github.com/usuario</li>37 </ul>38 </div>39</MainLayout>Conceptos practicados: Props múltiples, Astro.url.pathname, slots con nombre, routing basado en archivos, reutilización de layouts, clases condicionales.
Crear un Componente Reutilizable
Enunciado:
Crea un componente llamado Button.astro en la carpeta src/components/ que:
- • Acepte dos props:
text(el texto del botón) yurl(la URL a la que redirige) - • Renderice un enlace
<a>con estilos de botón - • Tenga un estilo CSS básico (color de fondo, padding, border-radius)
Luego, usa el componente 3 veces en una página para crear 3 botones diferentes.
Ver Solución
src/components/Button.astro
1---2const { text, url } = Astro.props;3---4 5<a href={url} class="button">{text}</a>6 7<style>8 .button {9 display: inline-block;10 padding: 0.75rem 1.5rem;11 background-color: #3b82f6;12 color: white;13 text-decoration: none;14 border-radius: 0.5rem;15 font-weight: 600;16 transition: background-color 0.3s;17 }18 19 .button:hover {20 background-color: #2563eb;21 }22</style>src/pages/ejemplo.astro (usando el componente)
1---2import Button from '../components/Button.astro';3---4 5<!DOCTYPE html>6<html lang="es">7<head>8 <meta charset="UTF-8">9 <title>Ejemplo de Botones</title>10</head>11<body>12 <h1>Mis Botones</h1>13 14 <Button text="Ir al inicio" url="/" />15 <Button text="Ver Blog" url="/blog" />16 <Button text="Contactar" url="/contacto" />17</body>18</html>Resumen
src/pages/ - Cada archivo = una ruta (routing basado en archivos) src/layouts/ - Plantillas reutilizables para estructura común src/components/ - Componentes UI reutilizables public/ - Archivos estáticos (imágenes, fuentes, favicon)