title | description | i18nReady |
---|---|---|
Colecciones de Contenido |
Las colecciones de contenido ayudan a organizar tu Markdown y a comprobar el tipo de sus datos de entrada. |
true |
import { FileTree } from '@astrojs/starlight/components';
import Since from '/components/Since.astro'
import RecipeLinks from "/components/RecipeLinks.astro"
import Badge from "~/components/Badge.astro"
Las Colecciones de contenido son la mejor manera de administrar y crear contenido en cualquier proyecto de Astro. Las colecciones ayudan a organizar tus documentos, validar tu frontmatter y proporcionar una seguridad de tipo automática de TypeScript para todo tu contenido.
Una colección de contenido es cualquier directorio de nivel superior dentro del directorio reservado src/content
del proyecto, como src/content/newsletter
y src/content/authors
. Solo se permiten colecciones de contenido dentro del directorio src/content
. Este directorio no se puede utilizar para nada más.
Una entrada de colección es cualquier pieza de contenido dentro de tu directorio de colecciones de contenido. Las entradas pueden usar formatos de autoría de contenido que incluyen Markdown (.md
) y MDX (.mdx
usando la integración MDX) o como uno de los dos formatos de datos admitidos: YAML (.yaml
) y JSON (.json
). Recomendamos usar un esquema de nomenclatura consistente (minúsculas, guiones en lugar de espacios) para tus archivos para facilitar la búsqueda y organización de tu contenido, pero esto no es obligatorio. También puedes excluir las entradas de ser construidas prefijando el nombre de archivo con un guión bajo (_).
Una vez que tengas una colección, puedes comenzar a consultar tu contenido utilizando las APIs de contenido integradas de Astro.
Astro guarda metadatos importantes para las colecciones de contenido en un directorio .astro
en tu proyecto. No es necesario que realices ninguna acción para mantener o actualizar este directorio. Se te recomienda que lo ignores por completo mientras trabajas en tu proyecto.
El directorio .astro
se actualizará automáticamente cada vez que ejecutes los comandos astro dev
, astro build
. Puedes ejecutar astro sync
en cualquier momento para actualizar el directorio .astro
manualmente.
:::tip
Si estás utilizando Git para el control de versiones, te recomendamos que ignores el directorio .astro
añadiendo .astro
a tu .gitignore
. Esto le dice a Git que ignore este directorio y cualquier archivo dentro de él.
echo "\n.astro" >> .gitignore
:::
Si dos archivos representan diferentes tipos de contenido (por ejemplo, una publicación de blog y un perfil de autor), probablemente pertenezcan a diferentes colecciones. Esto es importante porque muchas características (validación de frontmatter, seguridad de tipo automático de TypeScript) requieren que todas las entradas de una colección compartan una estructura similar.
Si puedes trabajar con diferentes tipos de contenido, debes crear múltiples colecciones para representar cada tipo. Puedes crear tantas colecciones diferentes en tu proyecto como desees.
- src/content/ - **newsletter/** - week-1.md - week-2.md - **blog/** - post-1.md - post-2.md - **authors/** - grace-hopper.json - alan-turing.jsonUna colección de contenido siempre es una carpeta de nivel superior dentro del directorio src/content/
. No puedes anidar una colección dentro de otra. Sin embargo, puedes usar subdirectorios para organizar tu contenido dentro de una colección.
Por ejemplo, puedes usar la siguiente estructura de directorios para organizar las traducciones de i18n dentro de una sola colección docs
. Cuando consultes esta colección, podrás filtrar el resultado por idioma utilizando la ruta del archivo.
:::note
El archivo src/content/config.ts
es opcional. Sin embargo, si eliges no definir tus colecciones, deshabilitarás algunas de sus mejores características como la validación del esquema del frontmatter o la generación automática de tipos de datos en TypeScript.
:::
Para aprovechar al máximo tus colecciones de contenido, crea un archivo src/content/config.ts
en tu proyecto (también se admiten las extensiones .js
y .mjs
). Este es un archivo especial que Astro cargará y utilizará automáticamente para configurar tus colecciones de contenido.
// src/content/config.ts
// 1. Importa las utilidades de `astro:content`
import { defineCollection } from 'astro:content';
// 2. Define tu colección(es)
const blogCollection = defineCollection({ /* ... */ });
// 3. Exporta un único objeto `collections` para registrar tu(s) colección(es)
// Esta clave debe coincidir con el nombre de tu directorio de colección en "src/content"
export const collections = {
'blog': blogCollection,
};
Si no extiendes las configuraciones recomendadas de TypeScript strict
o strictest
de Astro en tu archivo tsconfig.json
, es posible que debas actualizar tu tsconfig.json
para habilitar strictNullChecks
.
{
// Nota: No se necesita ningún cambio si usas "astro/tsconfigs/strict" o "astro/tsconfigs/strictest"
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"strictNullChecks": true
}
}
Si usas archivos .js
o .mjs
en un proyecto de Astro, puedes habilitar IntelliSense y la comprobación de tipos en tu editor habilitando allowJs
en tu tsconfig.json
:
{
// Nota: No se necesita ningún cambio si usas "astro/tsconfigs/strict" o "astro/tsconfigs/strictest"
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"strictNullChecks": true,
"allowJs": true
}
}
Los esquemas garantizan un frontmatter o datos de entrada consistentes dentro de una colección. Un esquema garantiza que estos datos existen en una forma predecible cuando necesitas hacer referencia o consultarlos. Si algún archivo viola su esquema de colección, Astro proporcionará un error útil para informarte.
Los esquemas también potencian las generación automática de tipos de TypeScript para tu contenido en Astro. Cuando defines un esquema para tu colección, Astro generará y aplicará automáticamente una interfaz de TypeScript. 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 definir tu primera colección, crea un archivo src/content/config.ts
si no existe (las extensiones .js
y .mjs
también son compatibles). Este archivo debe:
- Importar las utilidades adecuadas de
astro:content
. - Definir cada colección que deseas validar. Esto incluye un
type
(introducido en Astro v2.5.0) que especifica si la colección contiene formatos de autoría de contenido como Markdown (type: 'content'
) o formatos de datos como JSON o YAML (type: 'data'
). También incluye unschema
que define la forma de tu frontmatter o datos de entrada. - Exportar un único objeto
collections
para registrar tus colecciones.
// src/content/config.ts
// 1. Importar las utilidades de `astro:content`
import { z, defineCollection } from 'astro:content';
// 2. Definir un `type` y `schema` para cada colección
const blogCollection = defineCollection({
type: 'content', // v2.5.0 y posteriores
schema: z.object({
title: z.string(),
tags: z.array(z.string()),
image: z.string().optional(),
}),
});
// 3. Exportar un único objeto `collections` para registrar tu(s) colección(es)
export const collections = {
'blog': blogCollection,
};
Puedes usar defineCollection()
tantas veces como desees para crear múltiples esquemas. Todas las colecciones deben ser exportadas desde dentro del único objeto collections
.
// src/content/config.ts
const blogCollection = defineCollection({
type: 'content',
schema: z.object({ /* ... */ })
});
const newsletter = defineCollection({
type: 'content',
schema: z.object({ /* ... */ })
});
const authors = defineCollection({
type: 'data',
schema: z.object({ /* ... */ })
});
export const collections = {
'blog': blogCollection,
'newsletter': newsletter,
'authors': authors,
};
A medida que tu proyecto crece, también eres libre de reorganizar tu base de código y mover la lógica fuera del archivo src/content/config.ts
. Definir tus esquemas por separado puede ser útil para reutilizar esquemas en múltiples colecciones y compartir esquemas con otras partes de tu proyecto.
// src/content/config.ts
// 1. Importar tus utilidades y esquemas
import { defineCollection } from 'astro:content';
import { blogSchema, authorSchema } from '../schemas';
// 2. Definir tus colecciones
const blogCollection = defineCollection({
type: 'content',
schema: blogSchema,
});
const authorCollection = defineCollection({
type: 'data',
schema: authorSchema,
});
// 3. Exportar múltiples colecciones para registrarlas
export const collections = {
'blog': blogCollection,
'authors': authorCollection,
};
Puedes importar esquemas de colección desde cualquier lugar, incluyendo paquetes npm externos. Esto puede ser útil cuando trabajas con temas y bibliotecas que proporcionan sus propios esquemas de colección para que los uses.
// src/content/config.ts
import { blogSchema } from 'my-blog-theme';
const blogCollection = defineCollection({ type: 'content', schema: blogSchema });
// Exportar la colección de blog, usando un esquema externo de 'my-blog-theme'
export const collections = {
'blog': blogCollection,
};
Astro usa Zod para potenciar sus esquemas de contenido. Con Zod, Astro puede validar el frontmatter de cada archivo dentro de una colección y proporcionar tipos automáticos de TypeScript cuando consultas el contenido desde dentro de tu proyecto.
Para usar Zod en Astro, importa la utilidad z
de "astro:content"
. Esta es una re-exportación de la biblioteca Zod, y admite todas las funciones de Zod. Consulta el README de Zod para obtener documentación completa sobre cómo funciona Zod y qué funciones están disponibles.
// Ejemplo: Una hoja de trucos de muchos tipos de datos Zod comunes
import { z, defineCollection } from 'astro:content';
defineCollection({
schema: z.object({
isDraft: z.boolean(),
title: z.string(),
sortOrder: z.number(),
image: z.object({
src: z.string(),
alt: z.string(),
}),
author: z.string().default('Anonymous'),
language: z.enum(['en', 'es']),
tags: z.array(z.string()),
// Una propiedad opcional del frontmatter. ¡Muy común!
footnote: z.string().optional(),
// En el frontmatter, las fechas escritas sin comillas se interpretan como objetos Date
publishDate: z.date(),
// También puedes transformar un string de fecha (por ejemplo, "2022-07-08") a un objeto Date
// publishDate: z.string().transform((str) => new Date(str)),
// Avanzado: Valida que el string también sea un correo electrónico
authorContact: z.string().email(),
// Avanzado: Valida que el string también sea una URL
canonicalURL: z.string().url(),
})
})
Las entradas de una colección pueden "referenciar" otras entradas relacionadas.
Con la función reference()
de la API de Colecciones, puedes definir una propiedad en un esquema de colección como una entrada de otra colección. Por ejemplo, puedes requerir que cada entrada 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 a URL de publicaciones relacionadas almacenadas en la misma colección:
import { defineCollection, reference, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
// Referencia a un único autor de la colección `authors` por `id`
author: reference('authors'),
// Referencia a un arreglo de publicaciones relacionadas de la colección `blog` por `slug`
relatedPosts: z.array(reference('blog')),
})
});
const authors = defineCollection({
type: 'data',
schema: z.object({
name: z.string(),
portfolio: z.string().url(),
})
});
export const collections = { blog, authors };
Este ejemplo de publicación de blog especifica los slug
de las publicaciones relacionadas y el id
del autor de la publicación:
---
title: "Bienvenido a mi Blog"
author: ben-holmes # referencia `src/content/authors/ben-holmes.json`
relatedPosts:
- about-me # referencia `src/content/blog/about-me.md`
- my-year-in-review # referencia `src/content/blog/my-year-in-review.md`
---
Cuando usas type: 'content'
, cada entrada de contenido genera una propiedad slug
compatible con URL a partir de su id
de archivo. El slug se utiliza para consultar la entrada directamente desde tu colección. También es útil cuando creas nuevas páginas y URL a partir de tu contenido.
Puedes anular el slug generado de una entrada añadiendo tu propia propiedad slug
al frontmatter del archivo. Esto es similar a la función "permalink" de otros frameworks web. "slug"
es un nombre de propiedad especial y reservado que no está permitido en tu schema
de colección personalizado y no aparecerá en la propiedad data
de tu entrada.
---
title: Mi Publicación de Blog
slug: my-custom-slug/supports/slashes
---
El contenido de tu publicación de blog aquí.
Astro proporciona dos funciones para consultar una colección y devolver una (o más) entradas de contenido: getCollection()
y getEntry()
.
import { getCollection, getEntry } from 'astro:content';
// Obtén todas las entradas de una colección.
// Requiere el nombre de la colección como argumento.
// Ejemplo: recupera `src/content/blog/**`
const allBlogPosts = await getCollection('blog');
// Obtén una única entrada de colleción.
// Requiere el nombre de la colección y también
// el `slug` de la entrada (colecciones de contenido) o `id` (colecciones de datos)
// Ejemplo: recupera `src/content/authors/grace-hopper.json`
const graceHopperProfile = await getEntry('authors', 'grace-hopper');
Ambas funciones devuelven entradas de contenido tal como se definen en el tipo CollectionEntry
.
Cualquier referencia definida en tu esquema debe consultarse por separado después de consultar por primera vez la entrada de tu colección. Puedes usar la función getEntry()
de nuevo, o getEntries()
, para recuperar la entrada referenciada del objeto data
devuelto.
---
import { getEntry, getEntries } from 'astro:content';
const blogPost = await getEntry('blog', 'welcome');
// Resuelve una referencia singular
const author = await getEntry(blogPost.data.author);
// Resuelve un arreglo de referencias
const relatedPosts = await getEntries(blogPost.data.relatedPosts);
---
<h1>{blogPost.data.title}</h1>
<p>Autor: {author.data.name}</p>
<!-- ... -->
<h2>También te puede gustar:</h2>
{relatedPosts.map(p => (
<a href={p.slug}>{p.data.title}</a>
))}
getCollection()
toma un callback opcional "filter" que te permite filtrar tu consulta en función de las propiedades id
o data
(frontmatter) de una entrada. Para las colecciones de type: 'content'
, también puedes filtrar en función de slug
.
:::note
La propiedad slug
es específica de las colecciones de contenido y no estará disponible al filtrar colecciones de JSON o YAML.
:::
Puedes usar esto para filtrar por cualquier criterio de contenido que desees. Por ejemplo, puedes filtrar por propiedades como draft
para evitar que se publiquen publicaciones de blog en borrador en tu blog:
// Ejemplo: Filtra las entradas de contenido con `draft: true`
import { getCollection } from 'astro:content';
const publishedBlogEntries = await getCollection('blog', ({ data }) => {
return data.draft !== true;
});
También puedes crear páginas en borrador que estarán disponibles cuando ejecutes el servidor de desarrollo, pero que no se construirán en producción:
// Ejemplo: Filtrar las entradas de contenido con `draft: true` solo al construir para producción
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
Para filtrar argumentos 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 solo los elementos de un directorio anidado específico:
// Ejemplo: Filtra las entradas por subdirectorio en la colección
import { getCollection } from 'astro:content';
const englishDocsEntries = await getCollection('docs', ({ id }) => {
return id.startsWith('en/');
});
Una vez que hayas consultado tus entradas de colección, puedes acceder a cada entrada directamente dentro de la plantilla de tu componente de Astro. Esto te permite renderizar HTML para cosas como enlaces a tu contenido (usando el slug
de contenido) o información sobre tu contenido (usando la propiedad data
).
Para obtener información sobre cómo renderizar tu contenido a HTML, consulta Renderizando contenido a HTML a continuación.
---
// src/pages/index.astro
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog');
---
<ul>
{blogEntries.map(blogPostEntry => (
<li>
<a href={`/my-blog-url/${blogPostEntry.slug}`}>{blogPostEntry.data.title}</a>
<time datetime={blogPostEntry.data.publishedDate.toISOString()}>
{blogPostEntry.data.publishedDate.toDateString()}
</time>
</li>
))}
</ul>
Un componente también puede pasar un contenido completo como una prop.
Si haces esto, puedes usar la utilidad CollectionEntry
para tipar correctamente las props de tu componente usando TypeScript. Esta utilidad toma un argumento de tipo string que coincide con el nombre del esquema de tu colección y heredará todas las propiedades de ese esquema de colección.
---
// src/components/BlogCard.astro
import type { CollectionEntry } from 'astro:content';
interface Props {
post: CollectionEntry<'blog'>;
}
// `post` coincidirá con el tipo de esquema de tu colección 'blog'
const { post } = Astro.props;
---
Una vez consultado, puedes renderizar las entradas de Markdown y MDX a HTML usando la propiedad de función render()
de la entrada. Llamar a esta función te da acceso al contenido y metadatos renderizados, incluyendo tanto un componente <Content />
como una lista de todos los encabezados renderizados.
---
// src/pages/render-example.astro
import { getEntry } from 'astro:content';
const entry = await getEntry('blog', 'post-1');
const { Content, headings } = await entry.render();
---
<p>Publicado el: {entry.data.published.toDateString()}</p>
<Content />
Las Colecciones de contenido se almacenan fuera del directorio src/pages/
. Esto significa que no se generan rutas para los elementos de tu colección de forma predeterminada. Deberás crear manualmente una nueva ruta dinámica para generar páginas HTML a partir de las entradas de tu colección. Tu ruta dinámica asignará el parámetro de solicitud entrante (por ejemplo, Astro.params.slug
en src/pages/blog/[...slug].astro
) para recuperar la entrada correcta dentro de una colección.
El método exacto para generar rutas dependerá del modo de salida de tu compilación output
: 'static' (el valor predeterminado) o 'server' (para SSR).
Si estás construyendo un sitio web estático (el comportamiento predeterminado de Astro), debes usar la función getStaticPaths()
para crear múltiples páginas a partir de un solo componente src/pages/
durante tu compilación.
Llama getCollection()
dentro de getStaticPaths()
para consultar tu contenido o tu colección de datos. Luego, crea tus nuevas rutas URL usando la propiedad slug
(colecciones de contenido) o la propiedad id
(colecciones de datos) para cada entrada de contenido.
---
// src/pages/posts/[...slug].astro
import { getCollection } from 'astro:content';
// 1. Genera una nueva ruta para cada entrada de colección
export async function getStaticPaths() {
const blogEntries = await getCollection('blog');
return blogEntries.map(entry => ({
params: { slug: entry.slug }, props: { entry },
}));
}
// 2. Para tu plantilla, puedes obtener la entrada directamente de la prop
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<h1>{entry.data.title}</h1>
<Content />
Esto generará una nueva página para cada entrada en la colección blog
. Por ejemplo, una entrada en src/content/blog/hello-world.md
tendrá un slug de hello-world
, y por lo tanto su URL final será /posts/hello-world/
.
:::note
Si tus slugs personalizados contienen el carácter /
para producir URLs con múltiples segmentos de ruta, debes usar un parámetro rest ([...slug]
) en el nombre de archivo .astro
para esta página de enrutamiento dinámico.
:::
Si estás construyendo un sitio web dinámico (usando el soporte SSR de Astro), no se espera que generes ninguna ruta de antemano durante la compilación. En su lugar, tu página debe examinar la solicitud (usando Astro.request
o Astro.params
) para encontrar el slug
bajo demanda, y luego recuperarlo usando getEntry()
.
---
// src/pages/posts/[...slug].astro
import { getEntry } from "astro:content";
// 1. Obtén el slug de la solicitud entrante del servidor
const { slug } = Astro.params;
if (slug === undefined) {
throw new Error("Slug es requerido");
}
// 2. Consulta la entrada directamente usando el slug de la solicitud
const entry = await getEntry("blog", slug);
// 3. Redirige si la entrada no existe
if (entry === undefined) {
return Astro.redirect("/404");
}
// 4. (Opcional) Renderiza la entrada a HTML en la plantilla
const { Content } = await entry.render();
---
:::tip
¡Explora la carpeta src/pages/
del código de demostración del tutorial de blog en GitHub o abrelo en StackBlitz para ver ejemplos completos de cómo crear páginas a partir de tus colecciones para funciones de blog como una lista de publicaciones de blog, páginas de etiquetas y más!
:::
Si tienes un proyecto de Astro existente como un blog, que usa archivos Markdown o MDX en subcarpetas dentro de src/pages/
, considera migrar los archivos de contenido o datos relacionados a las colecciones de contenido.
Consulta cómo convertir un ejemplo básico de blog de src/pages/posts/
a src/content/posts
en nuestro tutorial paso a paso que utiliza la base de código del proyecto terminado del tutorial Crear un Blog.
Si estás trabajando con colecciones de tipo data
, Astro generará automáticamente archivos de esquema JSON para que tu editor obtenga IntelliSense y comprobación de tipos. Se creará un archivo separado para cada colección de datos en tu proyecto basado en las colecciones definidas en src/content/config.ts
utilizando una biblioteca llamada zod-to-json-schema
.
Esta carácateristica requiere que establezcas manualmente la ruta del archivo de tu esquema como el valor de $schema
en cada archivo de entrada de datos de la colección:
{
"$schema": "../../../.astro/collections/authors.schema.json",
"name": "Armand",
"skills": ["Astro", "Starlight"]
}
Alternativamente, puedes establecer este valor en la configuración de tu editor. Por ejemplo, para establecer este valor en la configuración json.schemas
de VSCode, proporciona la ruta de los archivos a coincidir y la ubicación de tu esquema JSON:
{
"json.schemas": [
{
"fileMatch": [
"/src/content/authors/**"
],
"url": "./.astro/collections/authors.schema.json"
}
]
}
Si estás trabajando con colecciones grandes, es posible que desees habilitar las compilaciones en caché con la bandera experimental.contentCollectionCache
. Esta característica experimental optimiza el proceso de compilación de Astro, permitiendo que las colecciones no modificadas se almacenen y reutilicen entre compilaciones.
En muchos casos, esto puede conducir a mejoras significativas en el rendimiento de la compilación.
Mientras esta característica se estabiliza, es posible que te encuentres con problemas con la caché almacenada. Siempre puedes restablecer tu caché de compilación ejecutando el siguiente comando:
npm run astro build -- --force
:::caution
No es recomendado. Los plugins de remark y rehype acceden al frontmatter raw del documento Markdown o MDX. Esto significa que el frontmatter remarkPluginFrontmatter
se maneja por separado de tu schema
de tipo seguro, y no reflejará ningún cambio o valor predeterminado aplicado a través de Astro. ¡Úsalo bajo tu propio riesgo!
:::
Astro admite los plugins remark o rehype que modifican tu frontmatter directamente. Puedes acceder a este frontmatter modificado dentro de una entrada de contenido usando la propiedad remarkPluginFrontmatter
devuelta de render()
:
---
import { getEntry } from 'astro:content';
const blogPost = await getEntry('blog', 'post-1');
const { remarkPluginFrontmatter } = await blogPost.render();
---
<p>{blogPost.data.title} — {remarkPluginFrontmatter.readingTime}</p>
<RecipeLinks slugs={["es/recipes/reading-time" ]}/>
Los pipelines de remark y rehype solo se ejecutan cuando se renderiza tu contenido, lo que explica por qué remarkPluginFrontmatter
solo está disponible después de llamar a render()
en tu entrada de contenido. En contraste, getCollection()
y getEntry()
no pueden devolver estos valores directamente porque no renderizan tu contenido.
Muchos formatos de fecha son admitidos en las colecciones de contenido, pero el esquema de tu colección debe coincidir con el formato utilizado en el frontmatter YAML de tu Markdown o MDX.
YAML usa el estándar ISO-8601 para expresar fechas. Utiliza el formato yyyy-mm-dd
(por ejemplo, 2021-07-28
) junto con un tipo de esquema de z.date()
:
---
title: Mi Publicación de Blog
pubDate: 2021-07-08
---
El formato de fecha se especificará en UTC si no se proporciona una zona horaria. Si necesitas especificar una zona horaria, puedes usar el formato ISO 8601.
---
title: Mi Publicación de Blog
pubDate: 2021-07-08T12:00:00-04:00
---
Para renderizar solo YYYY-MM-DD
de la marca de tiempo UTC completa, utiliza el método slice
de JavaScript para eliminar la marca de tiempo:
---
const { frontmatter } = Astro.props;
---
<h1>{frontmatter.title}</h1>
<p>{frontmatter.pubDate.toISOString().slice(0,10)}</p>
Para ver un ejemplo usando toLocaleDateString
para formatear el día, mes y año, consulta el componente <FormattedDate />
en la plantilla oficial del blog de Astro.