Перейти к содержимому

Коллекции контента

Добавлено в: astro@2.0.0

Коллекции контента — это лучший способ управления наборами контента в проектах Astro. Коллекции помогают организовывать документы, обеспечивают работу IntelliSense и проверку типов в редакторе, а также гарантируют автоматическую типобезопасность TypeScript для всего вашего контента.

В Astro v5.0 был представлен Content Layer API для определения и запроса коллекций контента. Этот производительный и масштабируемый API включает встроенные загрузчики для локального контента. Для удаленного контента можно использовать сторонние загрузчики или создавать свои собственные, чтобы получать данные из любого источника.

Вы можете определить коллекцию из набора данных со схожей структурой. Это может быть папка с постами блога, JSON-файл со списком товаров или любые данные, представляющие однотипные элементы.

Коллекции, хранящиеся локально, могут состоять из файлов Markdown, MDX, Markdoc, YAML, TOML или JSON:

  • Директорияsrc/
  • Директорияnewsletter/ коллекция “newsletter”
    • week-1.md запись коллекции
    • week-2.md запись коллекции
  • Директорияauthors/ коллекция “authors”
    • authors.json один файл со всеми записями

С помощью подходящего загрузчика вы также можете получать удаленные данные из внешних источников: CMS, баз данных или платежных систем.

Коллекции контента полагаются на TypeScript для валидации через Zod и проверки типов. Если вы не используете настройки strict или strictest, убедитесь, что в вашем tsconfig.json заданы следующие параметры:

tsconfig.json
{
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"strictNullChecks": true, // обязательно при использовании шаблона base
"allowJs": true // включено по умолчанию во всех шаблонах Astro
}
}

Для каждой коллекции используется функция defineCollection() для настройки:

  • загрузчика (loader) — обязателен;
  • схемы (schema) — необязательна, но крайне рекомендована для типобезопасности.

Для определения коллекций необходимо создать файл src/content.config.ts (поддерживаются также расширения .js и .mjs). Это специальный файл, который Astro использует для настройки:

src/content.config.ts
// 1. Импорт утилит из `astro:content`
import { defineCollection } from 'astro:content';
// 2. Импорт загрузчиков
import { glob, file } from 'astro/loaders';
// 3. Импорт Zod
import { z } from 'astro/zod';
// 4. Определение коллекций
const blog = defineCollection({ /* ... */ });
const dogs = defineCollection({ /* ... */ });
// 5. Экспорт объекта `collections` для регистрации
export const collections = { blog, dogs };

Content Layer API использует свойство loader для получения данных (локальных или удаленных).

Astro предоставляет два встроенных загрузчика (glob() и file()), а также инструменты для создания собственных.

Загрузчик glob() создает записи из папок с файлами Markdown, MDX, JSON и др. Он принимает pattern (глоб-шаблон) и base (путь к папке). ID каждой записи генерируется автоматически из имени файла. Используйте его, когда каждая запись — это отдельный файл.

Загрузчик file() создает несколько записей из одного локального файла. Каждая запись в файле должна иметь уникальный ключ id. Подходит для файлов, которые парсятся как массив объектов.

src/content.config.ts
import { defineCollection } from 'astro:content';
import { glob, file } from 'astro/loaders';
import { z } from 'astro/zod';
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
schema: /* ... */
});
const dogs = defineCollection({
loader: file("src/data/dogs.json"),
schema: /* ... */
});

Загрузчик file() принимает необязательный аргумент parser. Это позволяет использовать кастомные парсеры (например, csv-parse) для специфических форматов.

JSON и YAML парсятся автоматически. Для .csv или вложенных JSON-структур потребуется функция парсинга:

src/content.config.ts
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 })
})
});

Вы можете создать свой загрузчик для получения данных из CMS, API или базы данных. Это дает все преимущества коллекций (валидацию, типизацию) для внешних данных.

См. полный Content Loader API и примеры создания загрузчиков.

Схемы обеспечивают единообразие метаданных (frontmatter) или данных записи через валидацию Zod. Схема гарантирует, что данные существуют в предсказуемом формате. Если файл нарушает схему, Astro выдаст понятную ошибку.

Схемы также управляют типами TypeScript. Astro автоматически генерирует интерфейсы, что дает автодополнение и проверку типов при написании кода.

Пример определения схемы:

src/content.config.ts
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
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(),
})
});
См. справочник утилиты z для списка доступных типов данных Zod.

Записи одной коллекции могут ссылаться на записи другой. С помощью функции reference() можно связать, например, пост в блоге с профилем автора из другой коллекции.

src/content.config.ts
import { defineCollection, reference } from 'astro:content';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: "./src/data/blog" }),
schema: z.object({
title: z.string(),
author: reference('authors'), // ссылка по ID
relatedPosts: z.array(reference('blog')), // массив ссылок
})
});

Astro предоставляет функции для получения данных из коллекций:

  • getCollection() — возвращает массив всех записей.
  • getEntry() — возвращает одну запись по её ID.
import { getCollection, getEntry } from 'astro:content';
// Получить все посты
const allBlogPosts = await getCollection('blog');
// Получить конкретную собаку по ID
const poodleData = await getEntry('dogs', 'poodle');

Вы можете использовать данные коллекций прямо в компонентах Astro. Например, для создания списка ссылок:

---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
<h1>Мои посты</h1>
<ul>
{posts.map(post => (
<li><a href={`/blog/${post.id}`}>{post.data.title}</a></li>
))}
</ul>

Для отображения содержимого Markdown или MDX используйте функцию render(). Она возвращает компонент <Content /> и список заголовков headings.

---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('blog', 'post-1');
if (!entry) throw new Error('Пост не найден');
const { Content, headings } = await render(entry);
---
<h1>{entry.data.title}</h1>
<Content />

Функция getCollection() принимает необязательный колбэк для фильтрации данных:

// Пример: только опубликованные посты
const publishedPosts = await getCollection('blog', ({ data }) => {
return data.draft !== true;
});

Коллекции хранятся вне папки src/pages/, поэтому маршруты для них не создаются автоматически. Вам нужно создать динамический маршрут для генерации страниц.

Используйте getStaticPaths() для создания страниц во время сборки:

src/pages/posts/[id].astro
---
import { getCollection, render } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { id: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />

В режиме SSR страницы генерируются по запросу:

src/pages/posts/[id].astro
---
import { getEntry, render } from "astro:content";
const { id } = Astro.params;
const post = await getEntry("blog", id);
if (!post) return Astro.redirect("/404");
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />

Создавайте коллекцию, когда:

  • У вас есть группа данных с одинаковой структурой (посты, товары, вакансии).
  • Вы хотите использовать типобезопасность и автодополнение для метаданных.
  • Вы получаете данные из внешней CMS и хотите работать с ними через удобный API Astro.
  • Вам нужна высокая производительность и кеширование для тысяч записей.
  • Если у вас всего пара уникальных страниц (используйте обычные файлы в src/pages/).
  • Для файлов, которые не обрабатываются Astro (PDF, изображения в public/).
  • Если API источника данных обновляется в реальном времени и не подходит для сборки (используйте обычный fetch в режиме SSR).