Astro proporciona las páginas, layouts, componentes y renderizado del servidor para un sitio EmDash. Esta guía cubre los conceptos de Astro utilizados por las plantillas actuales de EmDash. Se asume que ya comprendes los temas de WordPress y las plantillas PHP.
Para funcionalidades del framework que no son específicas de EmDash, usa la documentación de Astro.
Estructura del proyecto
Un sitio Astro asigna a cada tipo de archivo un directorio explícito. Las plantillas actuales de EmDash utilizan esta estructura:
| WordPress | Astro | Propósito |
|---|---|---|
index.php, single.php, page.php | src/pages/ | Rutas URL |
template-parts/ | src/components/ | Markup reutilizable |
header.php y footer.php | src/layouts/ | Estructuras de página compartidas |
style.css | src/styles/ | Estilos del sitio |
| Configuración de plugins y base de datos | astro.config.mjs | Integraciones y adaptador de servidor |
| Datos de configuración del tema | seed/seed.json | Colecciones, menús y contenido de ejemplo |
La plantilla del blog utiliza directorios de rutas que coinciden con sus URLs públicas:
src/
├── components/
│ └── PostCard.astro
├── layouts/
│ └── Base.astro
├── pages/
│ ├── index.astro
│ ├── pages/
│ │ └── [slug].astro
│ └── posts/
│ ├── index.astro
│ └── [slug].astro
└── live.config.ts
Componentes Astro
Un componente .astro combina TypeScript del lado del servidor con una plantilla HTML. El código entre los delimitadores --- se ejecuta en el servidor. El markup debajo del segundo delimitador se convierte en el HTML de respuesta.
El siguiente componente declara props en su frontmatter y los renderiza en su plantilla:
---
interface Props {
title: string;
excerpt?: string;
href: string;
}
const { title, excerpt, href } = Astro.props;
---
<article>
<h2><a href={href}>{title}</a></h2>
{excerpt && <p>{excerpt}</p>}
</article>
Astro escapa los valores renderizados con {value}. Las importaciones, consultas a la base de datos y otras operaciones del servidor pertenecen al frontmatter.
Expresiones de plantilla
Las plantillas Astro usan llaves donde una plantilla PHP cambiaría a <?php ?>. Los patrones más comunes en las plantillas EmDash son valores, condiciones y mapeo de arrays:
| Objetivo | Sintaxis Astro |
|---|---|
| Imprimir un valor | {post.data.title} |
| Renderizar cuando existe un valor | {post.data.excerpt && <p>{post.data.excerpt}</p>} |
| Elegir entre dos resultados | {posts.length === 0 ? <p>Aún no hay publicaciones.</p> : <PostList />} |
| Renderizar una lista | {posts.map((post) => <PostCard title={post.data.title} excerpt={post.data.excerpt} href={"/posts/" + post.id} />)} |
La expresión puede usar variables preparadas en el frontmatter, valores de Astro.props o datos devueltos por una consulta EmDash. Astro escapa los valores de cadena por defecto; usa un renderizador como <PortableText /> para texto enriquecido estructurado en lugar de inyectar HTML.
Props y slots
Los props son comparables a los $args pasados a get_template_part(). Hacen que cada entrada sea explícita y pueden ser verificados por TypeScript.
Los slots permiten que un componente padre pase markup a un componente. Un slot por defecto es útil para el contenido de la página, mientras que los slots con nombre proporcionan puntos de inserción adicionales:
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<article>
<h2>{title}</h2>
<slot />
<footer><slot name="footer" /></footer>
</article>
La siguiente página llena ambos slots:
---
import Card from "../components/Card.astro";
---
<Card title="Última publicación">
<p>El contenido principal de la tarjeta.</p>
<a slot="footer" href="/posts/latest">Leer la publicación</a>
</Card>
Los slots son locales a la llamada del componente. No se comportan como las acciones de WordPress, que pueden recibir callbacks registrados en otro lugar.
Layouts
Un layout posee la estructura de documento compartida que un tema de WordPress a menudo divide entre header.php y footer.php. Las páginas importan el layout y pasan su contenido a través de su slot.
El siguiente layout proporciona una estructura de documento:
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
</head>
<body>
<header><a href="/">Mi sitio</a></header>
<main><slot /></main>
</body>
</html>
La siguiente página proporciona el título y el contenido principal del layout:
---
import Base from "../layouts/Base.astro";
---
<Base title="Inicio">
<h1>Últimas publicaciones</h1>
</Base>
Enrutamiento basado en archivos
Los archivos en src/pages/ definen rutas. Los nombres de archivo entre corchetes crean segmentos dinámicos.
| Archivo | URL |
|---|---|
src/pages/index.astro | / |
src/pages/posts/index.astro | /posts |
src/pages/posts/[slug].astro | /posts/hello-world |
src/pages/pages/[slug].astro | /pages/about |
Dentro de src/pages/posts/[slug].astro, Astro.params.slug contiene el valor de la URL. Lee Enrutamiento de Astro para parámetros rest, redirecciones y otras funcionalidades de enrutamiento.
Renderizado del servidor
Las plantillas actuales de EmDash usan output: "server" en astro.config.mjs. Una página puede por lo tanto consultar la base de datos en cada solicitud, de modo que el contenido publicado no depende de una nueva compilación estática.
No agregues getStaticPaths() a una ruta de tema EmDash a menos que el sitio trate deliberadamente a EmDash como una fuente de datos en tiempo de compilación. Los temas incluidos se renderizan en el servidor.
Lee Renderizado bajo demanda de Astro para el comportamiento a nivel de framework.
Consultar contenido EmDash
EmDash envuelve las colecciones de contenido en vivo de Astro con getEmDashCollection() y getEmDashEntry(). Los resultados de colecciones contienen un array entries. Los resultados de una sola entrada contienen entry, que es null cuando ninguna entrada publicada coincide.
El siguiente archivo usa el mismo ordenamiento e identificadores que la plantilla de blog actual:
---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
const { entries: posts, error } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
});
if (error) {
return new Response("No se pudieron cargar las publicaciones", { status: 500 });
}
---
<Base title="Publicaciones">
{posts.map((post) => (
<article>
<h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
{post.data.excerpt && <p>{post.data.excerpt}</p>}
</article>
))}
</Base>
post.id es el identificador de ruta expuesto por Astro y normalmente es el slug de la entrada. post.data.id es el identificador de la base de datos. Usa data.id cuando una API espera el ID de contenido almacenado, como funciones auxiliares de taxonomía o comentarios.
La siguiente ruta dinámica busca una publicación por el slug en la URL y renderiza su campo de Portable Text:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "../../layouts/Base.astro";
const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.redirect("/404");
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) return new Response("No se pudo cargar la publicación", { status: 500 });
if (!post) return Astro.redirect("/404");
---
<Base title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
</Base>
Continuar con Astro
Las plantillas de EmDash también usan estilos de componentes y pequeños scripts de navegador, pero esas son funcionalidades ordinarias de Astro y no conceptos de EmDash. Lee Estilos y CSS para estilos con alcance y globales, y Scripts y manejo de eventos cuando un componente necesita comportamiento del lado del navegador.