Выборка из коллекций
Описанную коллекцию читают функциями из модуля astro:content. getCollection() возвращает все записи, getEntry() — одну по её идентификатору, а render() превращает текст записи в компонент, который можно вставить в страницу.
Список статей
Откройте src/pages/posts/index.astro и замените выдуманные карточки настоящими статьями:
---
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import PostCard from '../../components/PostCard.astro';
const posts = await getCollection('blog');
---
<BaseLayout title="Статьи">
<h1>Статьи</h1>
{posts.map((post) => (
<PostCard title={post.data.title} url={`/posts/${post.id}`} />
))}
</BaseLayout>Откройте /posts — появится по карточке на каждый файл из src/content/blog. Во фронтматтере можно писать await сразу, без обёртки в асинхронную функцию.
Что лежит в записи
| Поле | Значение для first-post.md |
|---|---|
post.id | first-post — имя файла без расширения |
post.data | Проверенный схемой фронтматтер: title, pubDate, tags |
post.body | Исходный текст статьи в Markdown |
post.collection | blog |
post.data.pubDate — уже объект Date, потому что схема привела строку к дате.
Фильтр и сортировка
Вторым аргументом getCollection() принимает функцию-фильтр. Скроем черновики и отсортируем статьи от новых к старым:
---
import { getCollection } from 'astro:content';
const posts = (await getCollection('blog', ({ data }) => !data.draft))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---Статьи с draft: true во фронтматтере исчезнут из списка, а свежая статья окажется первой. Сортировка — обычный метод массива sort(): Astro не гарантирует порядок записей.
Одна запись и её текст
getEntry() находит запись по имени коллекции и id, а render() возвращает компонент Content с HTML статьи. Создайте src/pages/posts/first-post.astro:
---
import { getEntry, render } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
const post = await getEntry('blog', 'first-post');
if (!post) throw new Error('Статья не найдена');
const { Content } = await render(post);
---
<BaseLayout title={post.data.title}>
<h1>{post.data.title}</h1>
<Content />
</BaseLayout>Откройте /posts/first-post — появится заголовок и текст статьи, превращённый из Markdown в HTML. Делать такой файл для каждой статьи не придётся: следующий урок заменит его одной динамической страницей.
Частая ошибка
Пишут post.title вместо post.data.title и получают пустое место на странице. Всё, что задано во фронтматтере, лежит в post.data, а в самой записи — служебные поля вроде id. Редактор подсказывает правильный путь, если подключены типы Astro.