Opcional: Crear una colección de contenido
Ahora que tienes un blog usando el enrutamiento basado en archivos incorporado de Astro, lo actualizarás para usar una colección de contenido. Las colecciones de contenido son una forma poderosa de administrar grupos de contenido similar, como publicaciones de blog.
Prepárate para...
- Mueve tu carpeta de publicaciones de blog a
src/blog/
- Crea un esquema para definir el frontmatter de tu publicación de blog
- Usa
getCollection()
para obtener el contenido y los metadatos de la publicación de blog
Aprender: Páginas vs. Colecciones
Sección titulada Aprender: Páginas vs. ColeccionesIncluso al usar colecciones de contenido, seguirás utilizando la carpeta src/pages/
para páginas individuales, como tu página “Sobre mí”. Pero, mover tus publicaciones de blog fuera de esta carpeta especial te permitirá usar APIs más poderosas y de mejor rendimiento para generar el índice de tus publicaciones de blog y mostrar tus publicaciones de blog individuales.
Al mismo tiempo, recibirás una mejor guía y autocompletado en tu editor de código porque tendrás un esquema para definir una estructura común para cada publicación que Astro te ayudará a aplicar a través de Zod, una biblioteca de declaración y validación de esquemas para TypeScript. En tu esquema, puedes especificar cuándo las propiedades del frontmatter son obligatorias, como una descripción o un autor, y qué tipo de datos debe tener cada propiedad, como una cadena o una matriz. Esto lleva a detectar muchos errores antes, con mensajes de error descriptivos que te indican exactamente cuál es el problema.
Lee más sobre las colecciones de contenido de Astro en nuestra guía, o comienza con las instrucciones a continuación para convertir un blog básico de src/pages/posts/
a src/blog/
.
Pon a prueba tus conocimientos
Sección titulada Pon a prueba tus conocimientos- ¿Qué tipo de página probablemente mantendrías en
src/pages/
?
- ¿Cuál no es un beneficio de mover las publicaciones de blog a una colección de contenido?
- Las colecciones de contenido usan TypeScript …
Los siguientes pasos te muestran cómo extender el producto final del tutorial “Construye un Blog” creando una colección de contenido para las publicaciones de blog.
Actualizar dependencias
Sección titulada Actualizar dependenciasActualiza a la última versión de Astro y actualiza todas las integraciones a sus últimas versiones ejecutando los siguientes comandos en tu terminal:
# Actualiza Astro y las integraciones oficiales juntasnpx @astrojs/upgrade
# Actualiza Astro y las integraciones oficiales juntaspnpm dlx @astrojs/upgrade
# Actualiza Astro y las integraciones oficiales juntasyarn dlx @astrojs/upgrade
Crear una colección para tus publicaciones
Sección titulada Crear una colección para tus publicaciones-
Crea una nueva colección (carpeta) llamada
src/blog/
. -
Mueve todas tus publicaciones de blog existentes (archivos
.md
) desrc/pages/posts/
a esta nueva colección. -
Crea un archivo
src/content.config.ts
para definir un esquema para tupostsCollection
. Para el código del tutorial de blog existente, agrega el siguiente contenido al archivo para definir todas las propiedades del frontmatter utilizadas en sus publicaciones de blog:src/content.config.ts // Importa el cargador globimport { glob } from "astro/loaders";// Importa utilidades de `astro:content`import { z, defineCollection } from "astro:content";// Define un `loader` y un `schema` para cada colecciónconst blog = defineCollection({loader: glob({ pattern: '**/[^_]*.md', base: "./src/blog" }),schema: z.object({title: z.string(),pubDate: z.date(),description: z.string(),author: z.string(),image: z.object({url: z.string(),alt: z.string()}),tags: z.array(z.string())})});// Exporta un solo objeto `collections` para registrar tus coleccionesexport const collections = { blog }; -
Para que Astro reconozca tu esquema, cierra (
CTRL + C
) y reinicia el servidor de desarrollo para continuar con el tutorial. Esto definirá el móduloastro:content
.
Generar páginas desde una colección
Sección titulada Generar páginas desde una colección-
Crea un archivo de página llamado
src/pages/posts/[...slug].astro
. Tus archivos Markdown y MDX ya no se convierten automáticamente en páginas usando el enrutamiento basado en archivos de Astro cuando están dentro de una colección, por lo que debes crear una página responsable de generar cada publicación de blog individual. -
Agrega el siguiente código para consultar tu colección para que el slug de cada publicación de blog y el contenido de la página estén disponibles para cada página que generará:
src/pages/posts/[...slug].astro ---import { getCollection, render } from 'astro:content';export async function getStaticPaths() {const posts = await getCollection('blog');return posts.map(post => ({params: { slug: post.id }, props: { post },}));}const { post } = Astro.props;const { Content } = await render(post);--- -
Renderiza tu publicación
<Content />
dentro del diseño para páginas Markdown. Esto te permite especificar un diseño común para todas tus publicaciones.src/pages/posts/[...slug].astro ---import { getCollection, render } from 'astro:content';import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';export async function getStaticPaths() {const posts = await getCollection('blog');return posts.map(post => ({params: { slug: post.id }, props: { post },}));}const { post } = Astro.props;const { Content } = await render(post);---<MarkdownPostLayout frontmatter={post.data}><Content /></MarkdownPostLayout> -
Elimina la definición de
layout
en el frontmatter de cada publicación individual. Tu contenido ahora está envuelto en un diseño cuando se renderiza, y esta propiedad ya no es necesaria.src/content/posts/post-1.md ---layout: ../../layouts/MarkdownPostLayout.astrotitle: 'Mi primera publicación de blog'pubDate: 2022-07-01...---
Reemplazar import.meta.glob()
con getCollection()
Sección titulada Reemplazar import.meta.glob() con getCollection()-
En cualquier lugar donde tengas una lista de publicaciones de blog, como la página de Blog del tutorial (
src/pages/blog.astro/
), deberás reemplazarimport.meta.glob()
congetCollection()
(EN) como la forma de obtener contenido y metadatos de tus archivos Markdown.src/pages/blog.astro ---import { getCollection } from "astro:content";import BaseLayout from "../layouts/BaseLayout.astro";import BlogPost from "../components/BlogPost.astro";const pageTitle = "Mi Blog de Aprendizaje de Astro";const allPosts = Object.values(import.meta.glob("../pages/posts/*.md", { eager: true }));const allPosts = await getCollection("blog");--- -
También deberás actualizar las referencias a los datos devueltos para cada
post
. Ahora encontrarás los valores de tu frontmatter en la propiedaddata
de cada objeto. Además, al usar colecciones, cada objetopost
tendrá unslug
de página, no una URL completa.src/pages/blog.astro ---import { getCollection } from "astro:content";import BaseLayout from "../layouts/BaseLayout.astro";import BlogPost from "../components/BlogPost.astro";const pageTitle = "Mi Blog de Aprendizaje de Astro";const allPosts = await getCollection("blog");---<BaseLayout pageTitle={pageTitle}><p>Aquí es donde publicaré sobre mi viaje aprendiendo Astro.</p><ul>{allPosts.map((post) => (<BlogPost url={post.url} title={post.frontmatter.title} />)}<BlogPost url={`/posts/${post.id}/`} title={post.data.title} />))}</ul></BaseLayout> -
El proyecto de blog del tutorial también genera dinámicamente una página para cada etiqueta usando
src/pages/tags/[tag].astro
y muestra una lista de etiquetas ensrc/pages/tags/index.astro
.Aplica los mismos cambios que arriba a estos dos archivos:
- obtén datos sobre todas tus publicaciones de blog usando
getCollection("blog")
en lugar de usarimport.meta.glob()
- accede a todos los valores del frontmatter usando
data
en lugar defrontmatter
- crea una URL de página agregando el
slug
de la publicación a la ruta/posts/
La página que genera páginas de etiquetas individuales ahora se convierte en:
src/pages/tags/[tag].astro ---import { getCollection } from "astro:content";import BaseLayout from "../../layouts/BaseLayout.astro";import BlogPost from "../../components/BlogPost.astro";export async function getStaticPaths() {const allPosts = await getCollection("blog");const uniqueTags = [...new Set(allPosts.map((post) => post.data.tags).flat())];return uniqueTags.map((tag) => {const filteredPosts = allPosts.filter((post) =>post.data.tags.includes(tag));return {params: { tag },props: { posts: filteredPosts },};});}const { tag } = Astro.params;const { posts } = Astro.props;---<BaseLayout pageTitle={tag}><p>Publicaciones etiquetadas con {tag}</p><ul>{ posts.map((post) => <BlogPost url={`/posts/${post.id}/`} title={post.data.title} />) }</ul></BaseLayout>Pruébalo tú mismo - Actualiza la consulta en la página del Índice de Etiquetas
Sección titulada Pruébalo tú mismo - Actualiza la consulta en la página del Índice de EtiquetasImporta y usa
getCollection
para obtener las etiquetas utilizadas en las publicaciones de blog ensrc/pages/tags/index.astro
, siguiendo los mismos pasos que arriba.Muéstrame el código.
src/pages/tags/index.astro ---import { getCollection } from "astro:content";import BaseLayout from "../../layouts/BaseLayout.astro";const allPosts = await getCollection("blog");const tags = [...new Set(allPosts.map((post) => post.data.tags).flat())];const pageTitle = "Índice de Etiquetas";---<!-- ... --> - obtén datos sobre todas tus publicaciones de blog usando
Actualizar cualquier valor de frontmatter para que coincida con tu esquema
Sección titulada Actualizar cualquier valor de frontmatter para que coincida con tu esquemaSi es necesario, actualiza cualquier valor de frontmatter en todo tu proyecto, como en tu diseño, que no coincida con el esquema de tus colecciones.
En el ejemplo del tutorial del blog, pubDate
era una cadena. Ahora, según el esquema que define los tipos para el frontmatter de la publicación, pubDate
será un objeto Date
. Ahora puedes aprovechar esto para usar los métodos disponibles para cualquier objeto Date
para formatear la fecha.
Para renderizar la fecha en el diseño de la publicación del blog, conviértela en una cadena usando el método toLocaleDateString()
:
<!-- ... --><BaseLayout pageTitle={frontmatter.title}> <p>{frontmatter.pubDate.toLocaleDateString()}</p> <p><em>{frontmatter.description}</em></p> <p>Written by: {frontmatter.author}</p> <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} /><!-- ... -->
Actualizar la función RSS
Sección titulada Actualizar la función RSSEl proyecto de blog del tutorial incluye un feed RSS. Esta función también debe usar getCollection()
para devolver información de tus publicaciones de blog. Luego, generarás los elementos RSS usando el objeto data
devuelto.
import rss from '@astrojs/rss';import { pagesGlobToRssItems } from '@astrojs/rss';import { getCollection } from 'astro:content';
export async function GET(context) { const posts = await getCollection("blog"); return rss({ title: 'Astro Learner | Blog', description: 'Mi viaje aprendiendo Astro', site: context.site, items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')), items: posts.map((post) => ({ title: post.data.title, pubDate: post.data.pubDate, description: post.data.description, link: `/posts/${post.id}/`, })), customData: `<language>en-us</language>`, })}
Para el ejemplo completo del tutorial del blog usando colecciones de contenido, consulta la rama Content Collections del repositorio del tutorial.