14. Content Collections
Content Collections — это встроенная система Astro для управления контентом с типобезопасностью. Вместо хаоса папок с Markdown-файлами ты получаешь структурированные, валидированные коллекции с автодополнением TypeScript.
Думай о Content Collections как о легковесной базе данных прямо в файловой системе: каждая папка в src/content/ — это таблица, каждый файл — запись, а Zod-схема — это определение колонок.
Структура проекта
Заголовок раздела «Структура проекта»Все коллекции живут в папке src/content/:
src/ content/ config.ts ← схемы всех коллекций blog/ first-post.md second-post.mdx authors/ alex.json maria.yaml tags/ astro.json javascript.jsonОпределение коллекции в config.ts
Заголовок раздела «Определение коллекции в config.ts»import { defineCollection, z, reference } from 'astro:content';
const authorsCollection = defineCollection({ type: 'data', schema: z.object({ name: z.string(), bio: z.string(), avatar: z.string().url(), social: z.object({ twitter: z.string().optional(), github: z.string().optional(), }), }),});
const tagsCollection = defineCollection({ type: 'data', schema: z.object({ label: z.string(), color: z.string(), }),});
const blogCollection = defineCollection({ type: 'content', schema: z.object({ title: z.string(), description: z.string(), publishDate: z.date(), author: reference('authors'), // ← ссылка на другую коллекцию! tags: z.array(reference('tags')), draft: z.boolean().default(false), image: z.string().optional(), }),});
export const collections = { blog: blogCollection, authors: authorsCollection, tags: tagsCollection,};Zod-схемы: типобезопасный фронтматер
Заголовок раздела «Zod-схемы: типобезопасный фронтматер»Zod — это библиотека валидации, которую Astro использует для проверки данных в коллекциях:
z.string() // строкаz.number() // числоz.boolean() // булевоz.date() // дата (из строки ISO 8601)z.array(z.string()) // массив строкz.enum(['a', 'b']) // одно из значенийz.optional() // необязательное полеz.default(false) // значение по умолчаниюreference('authors') // ссылка на запись в другой коллекцииЕсли фронтматер файла не соответствует схеме, Astro выдаёт ошибку при сборке. Никаких undefined is not a function в рантайме!
Запросы к коллекциям
Заголовок раздела «Запросы к коллекциям»---import { getCollection, getEntry } from 'astro:content';
// Все публикации (кроме черновиков)const posts = await getCollection('blog', ({ data }) => !data.draft);
// Сортировка по датеconst sorted = posts.sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf());
// Конкретная записьconst author = await getEntry('authors', 'alex');
// Запись через reference-полеconst firstPost = posts[0];const postAuthor = await getEntry(firstPost.data.author);---Генерация страниц из коллекции
Заголовок раздела «Генерация страниц из коллекции»---import { getCollection } from 'astro:content';
export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(post => ({ params: { slug: post.slug }, props: { post }, }));}
const { post } = Astro.props;const { Content } = await post.render();---
<article> <h1>{post.data.title}</h1> <Content /></article>