Colecciones de contenido
Agregado en:
astro@2.0.0
Las colecciones de contenido son la mejor manera de gestionar conjuntos de contenido en cualquier proyecto de Astro: publicaciones de blog, descripciones de productos, perfiles de personajes, recetas o cualquier contenido estructurado. Las colecciones ayudan a organizar y consultar tus documentos, permiten el uso de Intellisense y la comprobación de tipos en tu editor, y proporcionan seguridad de tipos automática de TypeScript para todo tu contenido.
Astro proporciona APIs de alto rendimiento y escalables para cargar, consultar y renderizar contenido desde cualquier lugar: almacenado localmente en tu proyecto, alojado de forma remota u obtenido en vivo desde fuentes que se actualizan con frecuencia.
¿Qué son las colecciones de contenido?
Sección titulada “¿Qué son las colecciones de contenido?”Una colección de contenido es un conjunto de datos relacionados y estructuralmente idénticos. Estos datos se pueden almacenar en uno o varios archivos localmente (por ejemplo, una carpeta de archivos Markdown individuales de publicaciones de blog, un único archivo JSON de descripciones de productos) o se pueden obtener de fuentes remotas como una base de datos, CMS o un endpoint de API. Cada miembro de la colección se denomina entrada.
Directoriosrc/
- …
Directorionewsletter/ la colección “newsletter”
- week-1.md una entrada de colección
- week-2.md una entrada de colección
- week-3.md una entrada de colección
Directorioauthors/ la colección “author”
- authors.json un único archivo que contiene todas las entradas de la colección
Las colecciones se definen por la ubicación y la forma de sus entradas y proporcionan una manera conveniente de consultar y renderizar tu contenido y los metadatos asociados. Puedes crear una colección en cualquier momento en que tengas un grupo de datos o contenido relacionado, almacenado en la misma ubicación, que comparta una estructura común.
Hay dos tipos de colecciones de contenido disponibles para permitirte trabajar con datos obtenidos en tiempo de compilación o en tiempo de solicitud. Tanto las colecciones en tiempo de compilación como las colecciones de actualización en vivo utilizan:
- Un
loaderobligatorio para recuperar tu contenido y metadatos de donde estén almacenados y ponerlos a disposición de tu proyecto a través de APIs enfocadas en el contenido. - Un
schema(esquema) de colección opcional que te permite definir la forma esperada de cada entrada para la seguridad de tipos, el autocompletado y la validación en tu editor.
Las colecciones almacenadas localmente en tu proyecto o en tu sistema de archivos pueden utilizar uno de los cargadores en tiempo de compilación proporcionados por Astro para obtener datos de archivos Markdown, MDX, Markdoc, YAML, TOML o JSON. Apunta Astro a la ubicación de tu contenido, define la forma de tus datos, ¡y estarás listo con un blog o un sitio similar con mucho contenido y mayoritariamente estático en poco tiempo!
Con cargadores construidos por la comunidad o construyendo tú mismo un cargador de colección en tiempo de compilación personalizado o un cargador en vivo, puedes obtener datos remotos de cualquier fuente externa, como un CMS, una base de datos o un sistema de pago headless, ya sea en tiempo de compilación o en vivo bajo demanda.
Tipos de colecciones
Sección titulada “Tipos de colecciones”Las colecciones de contenido en tiempo de compilación se actualizan en el momento de la compilación, y los datos se guardan en una capa de almacenamiento. Esto proporciona un rendimiento excelente para la mayoría del contenido, pero puede no ser adecuado para fuentes de datos que se actualizan con frecuencia y requieren una frescura de datos al instante, como los precios de las acciones en tiempo real.
Para obtener el mejor rendimiento y escalabilidad, utiliza colecciones de contenido en tiempo de compilación cuando se cumpla uno o más de los siguientes puntos:
- El rendimiento es crítico y deseas prerenderizar datos en tiempo de compilación.
- Tus datos son relativamente estáticos (por ejemplo, publicaciones de blog, documentación, descripciones de productos).
- Deseas beneficiarte de la optimización en tiempo de compilación y el almacenamiento en caché.
- Necesitas procesar MDX o realizar optimización de imágenes.
- Tus datos se pueden obtener una vez y reutilizar en múltiples compilaciones.
Consulta la plantilla de inicio de blog oficial de Astro para ponerte en marcha rápidamente con un ejemplo del uso del cargador glob() integrado y la definición de un esquema para una colección de publicaciones de blog locales en Markdown o MDX.
Las colecciones de contenido en vivo obtienen sus datos en tiempo de ejecución en lugar de en tiempo de compilación. Esto te permite acceder a datos actualizados con frecuencia desde CMS, APIs, bases de datos u otras fuentes mediante una API unificada, sin necesidad de volver a compilar tu sitio cuando cambian los datos. Sin embargo, esto puede tener un costo de rendimiento ya que los datos se obtienen en cada solicitud y se devuelven directamente sin persistencia en el almacén de datos.
Las colecciones de contenido en vivo están diseñadas para datos que cambian con frecuencia y necesitan estar actualizados cuando se solicita una página. Considera usarlas cuando se cumpla uno o más de los siguientes puntos:
- Necesitas información en tiempo real (por ejemplo, datos específicos del usuario, niveles de existencias actuales).
- Deseas evitar compilaciones constantes para contenido que cambia a menudo.
- Tus datos se actualizan con frecuencia (por ejemplo, inventario de productos de último minuto, precios, disponibilidad).
- Necesitas pasar filtros dinámicos a tu fuente de datos en función de la entrada del usuario o los parámetros de la solicitud.
- Estás creando una funcionalidad de vista previa para un CMS donde los editores necesitan ver el contenido borrador de inmediato.
Ambos tipos de colecciones pueden existir en el mismo proyecto, por lo que siempre puedes elegir el mejor tipo de colección para cada fuente de datos individual. Por ejemplo, una colección en tiempo de compilación puede gestionar las descripciones de los productos, mientras que una colección en vivo puede gestionar el inventario de contenido.
Ambos tipos de colecciones utilizan APIs similares (por ejemplo, getCollection() y getLiveCollection()), de modo que trabajar con colecciones te resultará familiar independientemente de cuál elijas, al mismo tiempo que te aseguras de saber siempre con qué tipo de colección estás trabajando.
Sugerimos utilizar colecciones de contenido en tiempo de compilación siempre que sea posible, y utilizar colecciones en vivo cuando tu contenido necesite actualizarse en tiempo real y los compromisos de rendimiento sean aceptables. Además, las colecciones de contenido en vivo tienen algunas limitaciones en comparación con las colecciones en tiempo de compilación:
- Sin soporte para MDX: MDX no se puede renderizar en tiempo de ejecución
- Sin optimización de imágenes: Las imágenes no se pueden procesar en tiempo de ejecución
- Consideraciones de rendimiento: Los datos se obtienen en cada solicitud (a menos que se almacenen en caché)
- Sin persistencia en el almacén de datos: Los datos no se guardan en el almacén de datos de la capa de contenido
Cuándo crear una colección
Sección titulada “Cuándo crear una colección”Define tus datos como una colección cuando:
- Tengas múltiples archivos o datos que organizar que compartan la misma estructura general (por ejemplo, un directorio de publicaciones de blog escritas en Markdown que tengan todas las mismas propiedades de frontmatter).
- Tienes contenido existente almacenado de forma remota, como en un CMS, y deseas aprovechar las funciones de ayuda de las colecciones en lugar de usar
fetch()o SDKs. - Necesites obtener (decenas de) miles de datos relacionados en tiempo de compilación, y necesites un método de consulta y almacenamiento en caché que escale de forma adecuada.
Gran parte del beneficio de usar colecciones proviene de:
- Definir una forma de datos común para validar que una entrada individual sea “correcta” o “completa”, evitando errores en producción.
- APIs enfocadas en el contenido diseñadas para que las consultas sean intuitivas (por ejemplo,
getCollection()en lugar deimport.meta.glob()) al importar y renderizar contenido en tus páginas. - Acceso a cargadores integrados y acceso a la API de Content Loader de bajo nivel para recuperar tu contenido. Adicionalmente, hay varios cargadores de terceros y construidos por la comunidad disponibles, y puedes construir tu propio cargador personalizado para obtener datos desde cualquier lugar.
- Rendimiento y escalabilidad. Los datos de las colecciones de contenido en tiempo de compilación se pueden almacenar en caché entre compilaciones y son adecuados para decenas de miles de entradas de contenido.
Cuándo no crear una colección
Sección titulada “Cuándo no crear una colección”Las colecciones proporcionan una estructura, seguridad y organización excelentes cuando tienes varias piezas de contenido que deben compartir las mismas propiedades.
Es posible que las colecciones no sean tu solución si:
- Tienes solo una o un número pequeño de páginas de contenido diferentes. Considera crear componentes de página individuales como
src/pages/about.astrodirectamente con tu contenido en su lugar. - Estás mostrando archivos que Astro no procesa, como PDFs. Coloca estos activos estáticos en el directorio
public/de tu proyecto en su lugar. - Tu fuente de datos tiene su propio SDK/biblioteca cliente para importaciones que es incompatible con un cargador de contenido o no lo ofrece, y prefieres usarlo directamente.
Configuración de TypeScript para colecciones
Sección titulada “Configuración de TypeScript para colecciones”Las colecciones de contenido dependen de TypeScript para proporcionar la validación de Zod, Intellisense y la comprobación de tipos en tu editor. Por defecto, Astro configura una plantilla de TypeScript strict (estricta) cuando creas un nuevo proyecto utilizando el comando de la CLI create astro. Tanto la plantilla strict como la plantilla strictest de Astro incluyen la configuración de TypeScript que tu proyecto necesita para las colecciones de contenido.
Si cambiaste esta configuración a base porque no estás escribiendo TypeScript en tu proyecto, o no estás utilizando ninguna de las plantillas integradas de Astro, también necesitarás agregar las siguientes opciones de compilación (compilerOptions) en tu archivo tsconfig.json para usar colecciones de contenido:
{ "extends": "astro/tsconfigs/base", // not needed for `strict` or `strictest` "compilerOptions": { "strictNullChecks": true, "allowJs": true }}Definición de colecciones de contenido en tiempo de compilación
Sección titulada “Definición de colecciones de contenido en tiempo de compilación”Todas tus colecciones de contenido en tiempo de compilación se definen en un archivo especial src/content.config.ts (también se admiten las extensiones .js y .mjs) utilizando defineCollection(), y luego se exporta un único objeto de colecciones para usar en tu proyecto.
Cada colección individual configura:
- un
loaderen tiempo de compilación para una fuente de datos (obligatorio) - un
schemaen tiempo de compilación para la seguridad de tipos (opcional, ¡pero muy recomendado!)
// 1. Import utilities from `astro:content`import { defineCollection } from 'astro:content';
// 2. Import loader(s)import { glob, file } from 'astro/loaders';
// 3. Import Zodimport { z } from 'astro/zod';
// 4. Define a `loader` and `schema` for each collectionconst blog = defineCollection({ loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }), schema: z.object({ title: z.string(), description: z.string(), pubDate: z.coerce.date(), updatedDate: z.coerce.date().optional(), }),});
// 5. Export a single `collections` object to register your collection(s)export const collections = { blog };Luego puedes usar las funciones dedicadas getCollection() y getEntry() para consultar los datos de tus colecciones de contenido y renderizar tu contenido.
Puedes elegir generar rutas de página a partir de las entradas de tu colección en tiempo de compilación para un sitio completamente estático y prerenderizado. O bien, puedes renderizar tus colecciones en tiempo de compilación bajo demanda, optando por retrasar la construcción de tu página hasta que se solicite por primera vez. Esto es útil cuando tienes una gran cantidad de páginas (por ejemplo, miles o decenas de miles) y deseas retrasar la compilación de una página estática hasta que sea necesaria.
Cargadores de colecciones en tiempo de compilación
Sección titulada “Cargadores de colecciones en tiempo de compilación”Astro proporciona dos cargadores integrados (glob() y file()) para obtener tu contenido local en tiempo de compilación. Pasa la ubicación de tus datos en tu proyecto o en tu sistema de archivos, y estos cargadores manejarán automáticamente tus datos y actualizarán la capa de contenido del almacén de datos persistente.
Para obtener datos remotos en tiempo de compilación, puedes construir un cargador personalizado para recuperar tus datos y actualizar el almacén de datos. O bien, puedes usar cualquier integración de cargador de terceros o publicada por la comunidad. Ya existen varias para sistemas de gestión de contenidos populares, así como para fuentes de datos comunes como vaults de Obsidian, repositorios de GitHub o publicaciones de Bluesky.
El cargador glob()
Sección titulada “El cargador glob()”El cargador glob() obtiene entradas de directorios de archivos Markdown, MDX, Markdoc, JSON, YAML o TOML desde cualquier lugar del sistema de archivos. Si almacenas tus entradas de contenido localmente como archivos separados, como un directorio de publicaciones de blog, entonces el cargador glob() es todo lo que necesitas para acceder a tu contenido.
Este cargador requiere un patrón (pattern) de archivos de entrada a coincidir utilizando patrones glob compatibles con micromatch, y una ruta de archivo base (base) de dónde se encuentran tus archivos. Se generará automáticamente un id único para cada entrada a partir de su nombre de archivo, pero puedes definir IDs personalizados si es necesario.
import { defineCollection } from 'astro:content';import { glob } from 'astro/loaders';
const blog = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),});
export const collections = { blog };Definición de IDs personalizados
Sección titulada “Definición de IDs personalizados”Al usar el cargador glob() con archivos Markdown, MDX, Markdoc, JSON o TOML, cada id de entrada de contenido se genera automáticamente en un formato amigable para URL basado en el nombre del archivo de contenido. Este id único se utiliza para consultar la entrada directamente desde tu colección. También es útil al crear nuevas páginas y URLs a partir de tu contenido.
Puedes sobrescribir el id generado de una sola entrada agregando tu propia propiedad slug al frontmatter del archivo o al objeto de datos para los archivos JSON. Esto es similar a la característica de “permalink” de otros frameworks web.
---title: My Blog Postslug: my-custom-id/supports/slashes---Your blog post content here.{ "title": "My Category", "slug": "my-custom-id/supports/slashes", "description": "Your category description here."}También puedes pasar opciones a la función auxiliar generateID() del cargador glob() al definir tu colección en tiempo de construcción para ajustar cómo se generan los ids. Por ejemplo, es posible que desees revertir el comportamiento predeterminado de convertir letras mayúsculas a minúsculas para cada entrada de la colección:
import { glob } from "astro/loaders";import { defineCollection } from "astro:content";
const authors = defineCollection({ /* Retrieve all JSON files in your authors directory while retaining * uppercase letters in the ID. */ loader: glob({ pattern: "**/*.json", base: "./src/data/authors", generateId: ({ entry }) => entry.replace(/\.json$/, ""), }),});El cargador file()
Sección titulada “El cargador file()”El cargador file() obtiene múltiples entradas de un solo archivo local definido en tu colección. El cargador file() detectará y analizará automáticamente (según la extensión del archivo) una sola matriz de objetos de archivos JSON y YAML, y tratará cada tabla de nivel superior como una entrada independiente en archivos TOML.
import { defineCollection } from "astro:content";import { file } from "astro/loaders";
const dogs = defineCollection({ loader: file("src/data/dogs.json"),});
export const collections = { dogs };Cada objeto de entrada en el archivo debe tener una propiedad de clave id única para que la entrada pueda ser identificada y consultada. A diferencia del cargador glob(), el cargador file() no generará IDs automáticamente para cada entrada.
Puedes proporcionar tus entradas como una matriz de objetos con una propiedad id, o en forma de objeto donde el id único es la clave:
// Specify an `id` property in each object of an array[ { "id": "poodle", "coat": "curly", "shedding": "low" }, { "id": "afghan", "coat": "short", "shedding": "low" }]// Each key will be used as the `id`{ "poodle": { "coat": "curly", "shedding": "low" }, "afghan": { "coat": "silky", "shedding": "low" }}Analizar otros formatos de datos
Sección titulada “Analizar otros formatos de datos”El soporte para analizar archivos JSON, YAML y TOML individuales en entradas de colección con el cargador file() es integrado (a menos que tengas un documento JSON anidado). Para cargar tu colección desde tipos de archivos no admitidos, como .csv, necesitarás crear una función parser (analizador). Esta función se puede hacer asíncrona si es necesario (por ejemplo, para obtener archivos de la web o si tu analizador es asíncrono).
El siguiente ejemplo muestra la importación de un analizador CSV de terceros y luego el paso de una función parser personalizada al cargador file():
import { defineCollection } from "astro:content";import { file } from "astro/loaders";import { parse as parseCsv } from "csv-parse/sync";
const cats = defineCollection({ loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true }), }),});Documentos .json anidados
Sección titulada “Documentos .json anidados”El argumento parser() se puede utilizar para cargar una sola colección desde un documento JSON anidado. Por ejemplo, este archivo JSON contiene múltiples colecciones:
{"dogs": [{}], "cats": [{}]}Puedes separar estas colecciones pasando una función parser() personalizada al cargador file() para cada colección, utilizando el análisis JSON integrado de Astro:
import { file } from "astro/loaders";import { defineCollection } from "astro:content";
const dogs = defineCollection({ loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).dogs })});const cats = defineCollection({ loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).cats })});Cargadores personalizados en tiempo de compilación
Sección titulada “Cargadores personalizados en tiempo de compilación”Puedes construir un cargador personalizado utilizando la API de Content Loader para obtener contenido remoto de cualquier fuente de datos, como un CMS, una base de datos o un endpoint de API.
Luego puedes importar y definir tu cargador personalizado en la configuración de tus colecciones, pasando los valores requeridos:
import { defineCollection } from "astro:content";import { myLoader } from "./loader.ts";
const blog = defineCollection({ loader: myLoader({ url: "https://api.example.com/posts", apiKey: "my-secret", }),});Encuentra cargadores creados por la comunidad y de terceros en el directorio de integraciones de Astro.
El uso de un cargador personalizado para obtener tus datos creará automáticamente una colección a partir de tus datos remotos. Esto te brinda todos los beneficios de las colecciones locales, incluidos los ayudantes de la API específicos de la colección como getCollection() y render() para consultar y mostrar tus datos, así como la validación de esquemas.
De manera similar a la creación de una integración de Astro o un plugin de Vite, puedes distribuir tu cargador como un paquete npm para que otros lo utilicen en sus proyectos.
Definición del esquema de la colección
Sección titulada “Definición del esquema de la colección”Los esquemas imponen un frontmatter o datos de entrada coherentes dentro de una colección mediante la validación de Zod. Un esquema garantiza que estos datos existan en una forma predecible cuando necesites hacer referencia a ellos o consultarlos. Si algún archivo viola el esquema de su colección, Astro proporcionará un error útil para informártelo.
Los esquemas también potencian los tipados automáticos de TypeScript de Astro para tu contenido. Cuando defines un esquema para tu colección, Astro generará y aplicará automáticamente una interfaz de TypeScript a la misma. El resultado es un soporte completo de TypeScript cuando consultas tu colección, incluyendo el autocompletado de propiedades y la comprobación de tipos.
Para que Astro reconozca un esquema nuevo o actualizado, es posible que debas reiniciar el servidor de desarrollo o sincronizar la capa de contenido (s + enter) para definir el módulo astro:content.
Proporcionar un schema es opcional, ¡pero muy recomendado! Si eliges usar un esquema, entonces cada propiedad de frontmatter o de datos de las entradas de tu colección debe definirse utilizando un tipo de datos de Zod:
import { defineCollection } from "astro:content";import { z } from "astro/zod";import { glob, file } from "astro/loaders";
const blog = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }), schema: z.object({ title: z.string(), description: z.string(), pubDate: z.coerce.date(), updatedDate: z.coerce.date().optional(), }),});const dogs = defineCollection({ loader: file("src/data/dogs.json"), schema: z.object({ id: z.string(), breed: z.string(), temperament: z.array(z.string()), }),});
export const collections = { blog, dogs };Definición de tipos de datos con Zod
Sección titulada “Definición de tipos de datos con Zod”Astro utiliza Zod para potenciar sus esquemas de contenido. Con Zod, Astro puede validar los datos de cada archivo dentro de una colección y proporcionar tipos automáticos de TypeScript cuando consultas contenido desde dentro de tu proyecto.
Para usar Zod en Astro, importa la herramienta z desde "astro/zod". Esta es una reexportación de la biblioteca Zod y es compatible con todas las características de Zod 4.
z para obtener una guía rápida de los tipos de datos comunes y aprender cómo funciona Zod y qué características están disponibles.
Métodos de esquema de Zod
Sección titulada “Métodos de esquema de Zod”Todos los métodos de esquema de Zod (por ejemplo, .parse(), .transform()) están disponibles, con algunas limitaciones. Cabe destacar que realizar comprobaciones de validación personalizadas en imágenes utilizando image().refine() no es compatible.
Definición de referencias de colección
Sección titulada “Definición de referencias de colección”Las entradas de la colección también pueden hacer “referencia” a otras entradas relacionadas.
Con la función reference(), puedes definir una propiedad en un esquema de colección como una entrada de otra colección. Por ejemplo, puedes requerir que cada entrada de space-shuttle incluya una propiedad pilot que utilice el propio esquema de la colección pilot para la comprobación de tipos, el autocompletado y la validación.
Un ejemplo común es una publicación de blog que hace referencia a perfiles de autor reutilizables almacenados como JSON, o URLs de publicaciones relacionadas almacenadas en la misma colección:
import { defineCollection, reference } from "astro:content";import { glob } from "astro/loaders";import { z } from "astro/zod";
const blog = defineCollection({ loader: glob({ base: "./src/content/blog", pattern: "**/*.{md,mdx}" }), schema: z.object({ title: z.string(), // Reference a single author from the `authors` collection by `id` author: reference("authors"), // Reference an array of related posts from the `blog` collection by `id` relatedPosts: z.array(reference("blog")), }),});
const authors = defineCollection({ loader: glob({ pattern: "**/*.json", base: "./src/data/authors" }), schema: z.object({ name: z.string(), portfolio: z.url(), }),});
export const collections = { blog, authors };Esta publicación de blog de ejemplo especifica los ids de las publicaciones relacionadas y el id del autor de la publicación:
---title: "Welcome to my blog"author: ben-holmes # references `src/data/authors/ben-holmes.json`relatedPosts:- about-me # references `src/content/blog/about-me.md`- my-year-in-review # references `src/content/blog/my-year-in-review.md`---Estas referencias se transformarán en objetos que contienen una clave collection y una clave id, lo que te permite consultarlas fácilmente en tus plantillas.
Consulta de colecciones en tiempo de compilación
Sección titulada “Consulta de colecciones en tiempo de compilación”Astro proporciona funciones de ayuda para consultar una colección en tiempo de compilación y devolver una o más entradas de contenido.
getCollection()obtiene una colección completa y devuelve una matriz de entradas.getEntry()obtiene una sola entrada de una colección.
Estas devuelven entradas con un id único, un objeto data con todas las propiedades definidas, y también devolverán un body que contiene el cuerpo bruto sin compilar de un documento Markdown, MDX o Markdoc.
---import { getCollection, getEntry } from 'astro:content';
// Get all entries from a collection.// Requires the name of the collection as an argument.const allBlogPosts = await getCollection('blog');
// Get a single entry from a collection.// Requires the name of the collection and `id`const poodleData = await getEntry('dogs', 'poodle');---El orden de clasificación de las colecciones generadas no es determinista y depende de la plataforma. Esto significa que si estás llamando a getCollection() y necesitas que tus entradas se devuelvan en un orden específico (por ejemplo, publicaciones de blog ordenadas por fecha), debes ordenar las entradas de la colección tú mismo:
---import { getCollection } from 'astro:content';
const posts = (await getCollection('blog')).sort( (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),);---CollectionEntry.
Uso de contenido en las plantillas de Astro
Sección titulada “Uso de contenido en las plantillas de Astro”Después de consultar tus colecciones, puedes acceder al contenido y los metadatos de cada entrada directamente dentro de la plantilla de tu componente de Astro.
Por ejemplo, puedes crear una lista de enlaces a tus publicaciones de blog, mostrando la información del frontmatter de tu entrada utilizando la propiedad data:
---import { getCollection } from 'astro:content';const posts = await getCollection('blog');---<h1>My posts</h1><ul> {posts.map(post => ( <li><a href={`/blog/${post.id}`}>{post.data.title}</a></li> ))}</ul>Renderizado del contenido del cuerpo
Sección titulada “Renderizado del contenido del cuerpo”Una vez consultadas, puedes renderizar entradas Markdown y MDX a HTML utilizando la función render() de astro:content. Llamar a esta función te da acceso al contenido HTML renderizado, incluyendo tanto un componente <Content /> como una lista de todos los encabezados renderizados.
---import { getEntry, render } from "astro:content";
const entry = await getEntry("blog", "post-1");
if (!entry) { throw new Error("Entry not found");}
const { Content } = await render(entry);---
<h1>{entry.data.title}</h1><p>Published on: {entry.data.pubDate.toDateString()}</p><Content /><Content /> para reemplazar elementos HTML con alternativas personalizadas.
Pasar contenido como props
Sección titulada “Pasar contenido como props”Un componente también puede pasar una entrada de colección completa como una prop.
Puedes utilizar la utilidad CollectionEntry para tipar correctamente las props de tu componente utilizando TypeScript. Esta utilidad toma un argumento de tipo cadena que coincide con el nombre de tu esquema de colección y heredará todas las propiedades del esquema de esa colección.
---import type { CollectionEntry } from 'astro:content';interface Props { post: CollectionEntry<'blog'>;}
// `post` will match your 'blog' collection schema typeconst { post } = Astro.props;---Filtrado de consultas de colección
Sección titulada “Filtrado de consultas de colección”getCollection() toma una función callback de “filtro” opcional que te permite filtrar tu consulta en función de las propiedades id o data de una entrada.
Puedes utilizar esto para filtrar por cualquier criterio de contenido que desees. Por ejemplo, puedes filtrar por propiedades como draft (borrador) para evitar que las publicaciones de blog en borrador se publiquen en tu blog:
---// Example: Filter out content entries with `draft: true`import { getCollection } from 'astro:content';const publishedBlogEntries = await getCollection('blog', ({ data }) => { return data.draft !== true;});---También puedes crear páginas de borrador que estén disponibles cuando se ejecuta el servidor de desarrollo, pero que no se compilan en producción:
---// Example: Filter out content entries with `draft: true` only when building for productionimport { getCollection } from 'astro:content';const blogEntries = await getCollection('blog', ({ data }) => { return import.meta.env.PROD ? data.draft !== true : true;});---El argumento de filtro también admite el filtrado por directorios anidados dentro de una colección. Dado que el id incluye la ruta anidada completa, puedes filtrar por el inicio de cada id para devolver únicamente los elementos de un directorio anidado específico:
---// Example: Filter entries by sub-directory in the collectionimport { getCollection } from 'astro:content';const englishDocsEntries = await getCollection('docs', ({ id }) => { return id.startsWith('en/');});---Acceso a datos referenciados
Sección titulada “Acceso a datos referenciados”Para acceder a las referencias definidas en tu esquema, primero consulta la entrada de tu colección. Tus referencias estarán disponibles en el objeto data devuelto. (Por ejemplo, entry.data.author y entry.data.relatedPosts)
Luego, puedes usar la función getEntry() nuevamente (o getEntries() para recuperar múltiples entradas referenciadas) pasando esos valores devueltos. La función reference() de tu esquema transforma esos valores en uno o más objetos collection e id como una forma conveniente de consultar estos datos relacionados.
---import { getEntry, getEntries } from "astro:content";
// First, query a blog postconst blogPost = await getEntry("blog", "Adventures in Space");
// If the blog post doesn't exist, throw an errorif (!blogPost) { throw new Error("Blog post not found");}
// Retrieve a single reference item: the blog post's author// Equivalent to querying `{collection: "authors", id: "ben-holmes"}`const author = await getEntry(blogPost.data.author);
// Retrieve an array of referenced items: all the related posts// Equivalent to querying `[{collection: "blog", id: "visiting-mars"}, {collection: "blog", id: "leaving-earth-for-the-first-time"}]`const relatedPosts = await getEntries(blogPost.data.relatedPosts);---
<h1>{blogPost.data.title}</h1><p>Author: {author.data.name}</p>
<!-- ... -->
<h2>You might also like:</h2>{relatedPosts.map((post) => <a href={post.id}>{post.data.title}</a>)}Generación de rutas a partir del contenido
Sección titulada “Generación de rutas a partir del contenido”Las colecciones de contenido se almacenan fuera del directorio src/pages/. Esto significa que por defecto no se generan páginas ni rutas para los elementos de tu colección mediante el enrutamiento basado en archivos de Astro.
Deberás crear manualmente una nueva ruta dinámica si deseas generar páginas HTML para cada una de las entradas de tu colección, como las publicaciones de blog individuales. Tu ruta dinámica asignará el parámetro de solicitud entrante (por ejemplo, Astro.params.id en src/pages/blog/[...id].astro) para obtener la entrada correcta para cada página.
El método exacto para generar rutas dependerá de si tus páginas se pre-renderizan (por defecto) o se renderizan bajo demanda por un servidor.
Compilación para salida estática (por defecto)
Sección titulada “Compilación para salida estática (por defecto)”Si estás compilando un sitio web estático (comportamiento predeterminado de Astro) con colecciones en tiempo de compilación, utiliza la función getStaticPaths() para crear múltiples páginas a partir de un solo componente de página (por ejemplo, src/pages/[id].astro) durante tu compilación.
Llama a getCollection() dentro de getStaticPaths() para que los datos de tu colección estén disponibles para construir rutas estáticas. Luego, crea las rutas de URL individuales utilizando la propiedad id de cada entrada de contenido. Cada página recibe la entrada de colección completa como una prop para usar en tu plantilla de página.
---import { getCollection, render } from 'astro:content';// 1. Generate a new path for every collection entryexport async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(post => ({ params: { id: post.id }, props: { post }, }));}// 2. For your template, you can get the entry directly from the propconst { post } = Astro.props;const { Content } = await render(post);---<h1>{post.data.title}</h1><Content />Esto generará una ruta de página para cada entrada en la colección blog. Por ejemplo, una entrada en src/blog/hello-world.md tendrá un id de hello-world, y por lo tanto su URL final será /posts/hello-world/.
Si tus slugs personalizados contienen el carácter / para producir URLs con múltiples segmentos de ruta, debes usar un parámetro de resto (por ejemplo, [...id]) en el nombre de archivo .astro para esta página de enrutamiento dinámico.
Construcción de rutas bajo demanda al momento de la solicitud
Sección titulada “Construcción de rutas bajo demanda al momento de la solicitud”Con un adaptador instalado para el renderizado bajo demanda, puedes generar tus rutas de página dinámicas al momento de la solicitud. Primero, examina la solicitud (utilizando Astro.request o Astro.params) para encontrar el slug bajo demanda, y luego obtenlo utilizando una de las funciones de ayuda de colecciones de contenido de Astro:
getEntry()para páginas de colecciones en tiempo de compilación que se generan una vez, en la primera solicitud.getLiveEntry()para páginas de colecciones en vivo donde los datos se obtienen (o vuelven a obtener) en cada solicitud.
---export const prerender = false; // Not needed in 'server' mode
import { getEntry, render } from "astro:content";
// 1. Get the slug from the incoming server requestconst { id } = Astro.params;if (id === undefined) { return Astro.redirect("/404");}
// 2. Query for the entry directly using the request slugconst post = await getEntry("blog", id);
// 3. Redirect if the entry does not existif (post === undefined) { return Astro.redirect("/404");}
// 4. Render the entry to HTML in the templateconst { Content } = await render(post);---<h1>{post.data.title}</h1><Content />Explora la carpeta src/pages/ del código de demostración del tutorial de blog en GitHub para ver ejemplos completos de la creación de páginas dinámicas a partir de tus colecciones para características de blog como una lista de publicaciones, páginas de etiquetas, ¡y más!
Colecciones de contenido en vivo
Sección titulada “Colecciones de contenido en vivo”Las colecciones en vivo utilizan una API diferente a la de las colecciones de contenido en tiempo de compilación, aunque la configuración y las funciones de ayuda están diseñadas para resultar familiares.
Las diferencias clave incluyen:
- Tiempo de ejecución: Se ejecuta en tiempo de solicitud en lugar de en tiempo de compilación
- Archivo de configuración: Utiliza
src/live.config.tsen lugar desrc/content.config.ts - Definición de colección: Utiliza
defineLiveCollection()en su lugar dedefineCollection() - API del Loader: Implementa los métodos
loadCollectionyloadEntryen lugar del métodoload - Retorno de datos: Devuelve los datos directamente en lugar de almacenarlos en el almacén de datos
- Funciones de cara al usuario: Utiliza
getLiveCollection()/getLiveEntry()en lugar degetCollection()/getEntry()
Además, debes tener un adaptador configurado para el renderizado bajo demanda de los datos de las colecciones en vivo.
Define tus colecciones en vivo en el archivo especial src/live.config.ts (independiente de tu src/content.config.ts para colecciones en tiempo de compilación, si tienes uno).
Cada colección individual configura:
- un
loaderen vivo para tu fuente de datos, y opcionalmente para la seguridad de tipos (obligatorio) - un
schemade colección en vivo para la seguridad de tipos (opcional)
A diferencia de las colecciones en tiempo de compilación, no hay cargadores en vivo integrados disponibles. Deberás crear un cargador en vivo personalizado para tu fuente de datos específica o buscar un cargador de terceros para pasarlo a la propiedad loader de tu colección en vivo.
Opcionalmente puedes incluir la seguridad de tipos en tus cargadores en vivo. Por lo tanto, definir un schema de Zod para las colecciones en vivo es opcional. Sin embargo, si proporcionas uno, tendrá prioridad sobre los tipos del cargador en vivo.
// Define live collections for accessing real-time dataimport { defineLiveCollection } from 'astro:content';import { storeLoader } from '@mystore/astro-loader';
const products = defineLiveCollection({ loader: storeLoader({ apiKey: process.env.STORE_API_KEY, endpoint: 'https://api.mystore.com/v1', }),});
// Export a single `collections` object to register your collection(s)export const collections = { products };Luego puedes usar las funciones dedicadas getLiveCollection() y getLiveEntry() para acceder a tus datos en vivo y renderizar tu contenido.
Puedes generar rutas de página a partir de las entradas de tu colección en vivo bajo demanda, obteniendo tus datos frescos en tiempo de ejecución en cada solicitud sin necesidad de volver a compilar tu sitio como lo hacen las colecciones en tiempo de compilación. Esto es útil cuando acceder a datos actualizados al momento es más importante que tener tu contenido disponible en una capa de almacenamiento de datos de alto rendimiento que persiste entre las compilaciones del sitio.
Creación de un cargador en vivo
Sección titulada “Creación de un cargador en vivo”Puedes construir un cargador en vivo personalizado utilizando la API de Live Loader para obtener contenido remoto fresco a solicitud desde cualquier fuente de datos, como un CMS, una base de datos o un endpoint de API. Tendrás que indicarle a tu cargador en vivo cómo obtener y devolver entradas de contenido desde tu fuente de datos deseada, así como proporcionar el manejo de errores para las solicitudes de datos fallidas.
El uso de un cargador en vivo para obtener tus datos creará automáticamente una colección a partir de tus datos remotos. Esto te brinda todos los beneficios de las colecciones de contenido de Astro, incluidos los ayudantes de la API específicos de la colección como getLiveCollection() y render() para consultar y mostrar tus datos, así como un manejo de errores útil.
Encuentra cargadores en vivo creados por la comunidad y de terceros en el directorio de integraciones de Astro.
Uso de esquemas de Zod con colecciones en vivo
Sección titulada “Uso de esquemas de Zod con colecciones en vivo”Puedes usar esquemas de Zod con colecciones en vivo para validar y transformar datos en tiempo de ejecución. Esta validación de Zod funciona de la misma manera que los esquemas para colecciones en tiempo de compilación.
Cuando defines un esquema para una colección en vivo, tiene prioridad sobre los tipos del cargador en vivo al consultar la colección:
import { defineLiveCollection } from 'astro:content';import { z } from 'astro/zod';import { apiLoader } from './loaders/api-loader';
const products = defineLiveCollection({ loader: apiLoader({ endpoint: process.env.API_URL }), schema: z .object({ id: z.string(), name: z.string(), price: z.number(), // Transform the API's category format category: z.string().transform((str) => str.toLowerCase().replace(/\s+/g, '-')), // Coerce the date to a Date object createdAt: z.coerce.date(), }) .transform((data) => ({ ...data, // Add a formatted price field displayPrice: `$${data.price.toFixed(2)}`, })),});
export const collections = { products };Al usar esquemas de Zod con colecciones en vivo, los errores de validación se capturan automáticamente y se devuelven como objetos AstroError:
---export const prerender = false; // Not needed in 'server' mode
import { LiveCollectionValidationError } from 'astro/content/runtime';import { getLiveEntry } from 'astro:content';
const { entry, error } = await getLiveEntry('products', '123');
// You can handle validation errors specificallyif (LiveCollectionValidationError.is(error)) { console.error(error.message); return Astro.rewrite('/500');}
// TypeScript knows entry.data matches your Zod schema, not the loader's typeconsole.log(entry?.data.displayPrice); // e.g., "$29.99"---Acceso a datos en vivo
Sección titulada “Acceso a datos en vivo”Astro proporciona funciones de ayuda para colecciones en vivo para acceder a datos en vivo en cada solicitud y devolver una (o más) entradas de contenido. Estas se pueden usar de manera similar a sus contrapartes de colecciones en tiempo de compilación.
getLiveCollection()obtiene una colección completa y devuelve una matriz de entradas.getLiveEntry()obtiene una sola entrada de una colección.
Estas devuelven entradas con un id único y un objeto data con todas las propiedades definidas del cargador en vivo. Al usar cargadores de terceros o de la comunidad distribuidos como paquetes npm, consulta su propia documentación para conocer la forma esperada de los datos devueltos.
Puedes utilizar estas funciones para acceder a tus datos en vivo, pasando el nombre de la colección y opcionalmente condiciones de filtrado.
---export const prerender = false; // Not needed in 'server' mode
import { getLiveCollection, getLiveEntry } from "astro:content";
if (!Astro.params.slug) { return Astro.redirect('/404');}
// Use loader-specific filtersconst { entries: draftArticles } = await getLiveCollection("articles", { status: "draft", author: "john-doe",});
// Get a specific product by IDconst { entry: product } = await getLiveEntry("products", Astro.params.slug);---Renderizado de contenido
Sección titulada “Renderizado de contenido”Si tu cargador en vivo devuelve una propiedad rendered, puedes usar la función render() y el componente <Content /> para renderizar tu contenido directamente en tus páginas, utilizando el mismo método que las colecciones en tiempo de compilación.
También tienes acceso a cualquier error devuelto por el cargador en vivo, por ejemplo, para redirigir a una página 404 cuando no se puede mostrar el contenido:
---export const prerender = false; // Not needed in 'server' mode
if (!Astro.params.id) { return Astro.redirect("/404");}
import { getLiveEntry, render } from "astro:content";const { entry, error } = await getLiveEntry("articles", Astro.params.id);if (!entry || error) { return Astro.rewrite("/404");}
const { Content } = await render(entry);---
<h1>{entry.data.title}</h1><Content />Manejo de errores
Sección titulada “Manejo de errores”Los cargadores en vivo pueden fallar debido a problemas de red, errores de API o problemas de validación. La API está diseñada para hacer que el manejo de errores sea explícito.
Cuando llamas a getLiveCollection() o getLiveEntry(), el error será uno de los siguientes:
- El tipo de error definido por el cargador (si devolvió un error)
- Un
LiveEntryNotFoundErrorsi la entrada no fue encontrada - Un
LiveCollectionValidationErrorsi los datos de la colección no coinciden con el esquema esperado - Un
LiveCollectionCacheHintErrorsi la indicación de caché no es válida - Un
LiveCollectionErrorpara otros errores, como errores no capturados lanzados en el cargador
Puedes usar instanceof para verificar el tipo de un error en tiempo de ejecución:
---export const prerender = false; // Not needed in 'server' mode
import { LiveEntryNotFoundError } from "astro/content/runtime";import { getLiveEntry } from "astro:content";
if (!Astro.params.id) { return Astro.redirect("/404");}
const { entry, error } = await getLiveEntry("products", Astro.params.id);
if (error) { if (error instanceof LiveEntryNotFoundError) { console.error(`Product not found: ${error.message}`); Astro.response.status = 404; } else { console.error(`Error loading product: ${error.message}`); return Astro.redirect("/500"); }}---Almacenamiento en caché de datos en vivo
Sección titulada “Almacenamiento en caché de datos en vivo”Añadido en:
astro@7.0.0
Nuevo
Cuando los cargadores en vivo proporcionan indicaciones de caché (cache hints), getLiveEntry() y getLiveCollection() devuelven un objeto cacheHint. Esto te permite controlar el comportamiento del almacenamiento en caché de tus rutas sin configurar cabeceras manualmente.
Las indicaciones de caché incluyen etiquetas (tags) para una invalidación dirigida y la última fecha de modificación (lastModified) para mantener frescos los datos en caché. También puedes combinar las indicaciones de caché con tus propias opciones de caché para personalizar aún más el comportamiento de almacenamiento en caché.
Consulta la referencia del cargador de contenido (Content Loader Reference) para obtener más información sobre la implementación de las indicaciones de caché en tus cargadores en vivo.
Indicaciones de caché a nivel de entrada
Sección titulada “Indicaciones de caché a nivel de entrada”Pasa el cacheHint devuelto por getLiveEntry() a Astro.cache.set() para aplicar la estrategia de almacenamiento en caché recomendada por el cargador.
El siguiente ejemplo pasa la indicación de caché del cargador y agrega un maxAge para controlar cuánto tiempo permanece fresca la respuesta:
---import { getLiveEntry } from 'astro:content';
const { entry, error, cacheHint } = await getLiveEntry('products', Astro.params.id);
if (error) { return Astro.redirect('/404');}
if (cacheHint) { Astro.cache.set(cacheHint);}
Astro.cache.set({ maxAge: 300 });---
<h1>{entry.data.name}</h1>También puedes pasar un objeto LiveDataEntry directamente para permitir que Astro extraiga su cacheHint automáticamente:
---import { getLiveEntry } from 'astro:content';
const { entry, error } = await getLiveEntry('products', Astro.params.id);
if (error) { return Astro.redirect('/404');}
Astro.cache.set(entry);Astro.cache.set({ maxAge: 300, swr: 60 });---
<h1>{entry.data.name}</h1>Indicaciones de caché a nivel de colección
Sección titulada “Indicaciones de caché a nivel de colección”Al obtener una colección completa con getLiveCollection(), Astro fusiona las indicaciones de caché de la respuesta de la colección y de todas las entradas individuales: las etiquetas se acumulan y el lastModified más reciente gana.
El siguiente ejemplo pasa la indicación de caché combinada de una colección y establece una ventana de frescura de 10 minutos:
---import { getLiveCollection } from 'astro:content';
const { entries, error, cacheHint } = await getLiveCollection('products');
if (error) { return new Response('Error loading products', { status: 500 });}
if (cacheHint) { Astro.cache.set(cacheHint);}Astro.cache.set({ maxAge: 600 });---
<ul> {entries.map((p) => <li>{p.data.name}</li>)}</ul>Invalidación por entrada
Sección titulada “Invalidación por entrada”Puedes invalidar entradas almacenadas en caché pasando un objeto LiveDataEntry a cache.invalidate(). Esto te permite apuntar a respuestas en caché específicas para su invalidación basándose en las etiquetas de caché de la entrada, sin necesidad de vaciar toda la caché.
El siguiente ejemplo invalida la respuesta almacenada en caché para una entrada de producto específica:
import { getLiveEntry } from 'astro:content';
export async function POST(context) { const { entry } = await getLiveEntry('products', 'featured'); if (entry) { await context.cache.invalidate(entry); } return Response.json({ ok: true });}Uso de archivos de esquema JSON en tu editor
Sección titulada “Uso de archivos de esquema JSON en tu editor”Agregado en:
astro@4.13.0
Astro autogenera archivos JSON Schema para las colecciones, los cuales puedes usar en tu editor para obtener IntelliSense y comprobación de tipos para los archivos de datos.
Se genera un archivo JSON Schema para cada colección en tu proyecto y se escribe en el directorio .astro/collections/.
Por ejemplo, si tienes dos colecciones, una llamada authors y otra llamada posts, Astro generará .astro/collections/authors.schema.json y .astro/collections/posts.schema.json.
Usar esquemas JSON en archivos JSON
Puedes apuntar manualmente a un esquema generado por Astro estableciendo el campo $schema en tu archivo JSON.
El valor debe ser una ruta de archivo relativa desde el archivo de datos al esquema.
En el siguiente ejemplo, un archivo de datos en src/data/authors/ utiliza el esquema generado para la colección authors:
{ "$schema": "../../../.astro/collections/authors.schema.json", "name": "Armand", "skills": ["Astro", "Starlight"]}Usar un esquema para un grupo de archivos JSON en VS Code
En VS Code, puedes configurar un esquema para aplicarlo a todos los archivos de una colección utilizando la configuración json.schemas.
En el siguiente ejemplo, todos los archivos en el directorio src/data/authors/ utilizarán el esquema generado para la colección authors:
{ "json.schemas": [ { "fileMatch": ["/src/data/authors/**"], "url": "./.astro/collections/authors.schema.json" } ]}Usar esquemas en archivos YAML en VS Code
En VS Code, puedes agregar soporte para usar esquemas JSON en archivos YAML utilizando la extensión Red Hat YAML. Con esta extensión instalada, puedes hacer referencia a un esquema en un archivo YAML utilizando una sintaxis de comentario especial:
# yaml-language-server: $schema=../../../.astro/collections/authors.schema.jsonname: Armandskills: - Astro - StarlightUsar esquemas para un grupo de archivos YAML en VS Code
Con la extensión Red Hat YAML, puedes configurar un esquema para que se aplique a todos los archivos YAML en una colección utilizando la configuración yaml.schemas.
En el siguiente ejemplo, todos los archivos YAML en el directorio src/data/authors/ utilizarán el esquema generado para la colección authors:
{ "yaml.schemas": { "./.astro/collections/authors.schema.json": ["/src/content/authors/*.yml"] }}Consulta “Asociación de esquemas” (Associating schemas) en la documentación de la extensión Red Hat YAML para obtener más detalles.
Aprender