Коллекции контента
Добавлено в: astro@2.0.0
Коллекции контента — это лучший способ управления наборами контента в проектах Astro. Коллекции помогают организовывать документы, обеспечивают работу IntelliSense и проверку типов в редакторе, а также гарантируют автоматическую типобезопасность TypeScript для всего вашего контента.
В Astro v5.0 был представлен Content Layer API для определения и запроса коллекций контента. Этот производительный и масштабируемый API включает встроенные загрузчики для локального контента. Для удаленного контента можно использовать сторонние загрузчики или создавать свои собственные, чтобы получать данные из любого источника.
Проекты могут продолжать использовать старый API коллекций (представленный в Astro v2.0). Однако мы рекомендуем обновить существующие коллекции, когда появится возможность.
Что такое коллекции контента?
Заголовок раздела «Что такое коллекции контента?»Вы можете определить коллекцию из набора данных со схожей структурой. Это может быть папка с постами блога, JSON-файл со списком товаров или любые данные, представляющие однотипные элементы.
Коллекции, хранящиеся локально, могут состоять из файлов Markdown, MDX, Markdoc, YAML, TOML или JSON:
Директорияsrc/
- …
Директорияnewsletter/ коллекция “newsletter”
- week-1.md запись коллекции
- week-2.md запись коллекции
Директорияauthors/ коллекция “authors”
- authors.json один файл со всеми записями
С помощью подходящего загрузчика вы также можете получать удаленные данные из внешних источников: CMS, баз данных или платежных систем.
Настройка TypeScript
Заголовок раздела «Настройка TypeScript»Коллекции контента полагаются на TypeScript для валидации через Zod и проверки типов. Если вы не используете настройки strict или strictest, убедитесь, что в вашем tsconfig.json заданы следующие параметры:
{ "extends": "astro/tsconfigs/base", "compilerOptions": { "strictNullChecks": true, // обязательно при использовании шаблона base "allowJs": true // включено по умолчанию во всех шаблонах Astro }}Определение коллекций
Заголовок раздела «Определение коллекций»Для каждой коллекции используется функция defineCollection() для настройки:
- загрузчика (
loader) — обязателен; - схемы (
schema) — необязательна, но крайне рекомендована для типобезопасности.
Файл конфигурации коллекций
Заголовок раздела «Файл конфигурации коллекций»Для определения коллекций необходимо создать файл src/content.config.ts (поддерживаются также расширения .js и .mjs). Это специальный файл, который Astro использует для настройки:
// 1. Импорт утилит из `astro:content`import { defineCollection } from 'astro:content';
// 2. Импорт загрузчиковimport { glob, file } from 'astro/loaders';
// 3. Импорт Zodimport { z } from 'astro/zod';
// 4. Определение коллекцийconst blog = defineCollection({ /* ... */ });const dogs = defineCollection({ /* ... */ });
// 5. Экспорт объекта `collections` для регистрацииexport const collections = { blog, dogs };Настройка загрузчика (loader)
Заголовок раздела «Настройка загрузчика (loader)»Content Layer API использует свойство loader для получения данных (локальных или удаленных).
Встроенные загрузчики
Заголовок раздела «Встроенные загрузчики»Astro предоставляет два встроенных загрузчика (glob() и file()), а также инструменты для создания собственных.
Загрузчик glob() создает записи из папок с файлами Markdown, MDX, JSON и др. Он принимает pattern (глоб-шаблон) и base (путь к папке). ID каждой записи генерируется автоматически из имени файла. Используйте его, когда каждая запись — это отдельный файл.
Загрузчик file() создает несколько записей из одного локального файла. Каждая запись в файле должна иметь уникальный ключ id. Подходит для файлов, которые парсятся как массив объектов.
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: /* ... */});Функция parser
Заголовок раздела «Функция parser»Загрузчик file() принимает необязательный аргумент parser. Это позволяет использовать кастомные парсеры (например, csv-parse) для специфических форматов.
JSON и YAML парсятся автоматически. Для .csv или вложенных JSON-структур потребуется функция парсинга:
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 или базы данных. Это дает все преимущества коллекций (валидацию, типизацию) для внешних данных.
Готовые загрузчики от сообщества можно найти в каталоге интеграций Astro.
Определение схемы коллекции
Заголовок раздела «Определение схемы коллекции»Схемы обеспечивают единообразие метаданных (frontmatter) или данных записи через валидацию Zod. Схема гарантирует, что данные существуют в предсказуемом формате. Если файл нарушает схему, Astro выдаст понятную ошибку.
Схемы также управляют типами TypeScript. Astro автоматически генерирует интерфейсы, что дает автодополнение и проверку типов при написании кода.
Чтобы Astro увидел изменения в схеме, может потребоваться перезапуск сервера разработки или синхронизация через s + enter в терминале.
Пример определения схемы:
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() можно связать, например, пост в блоге с профилем автора из другой коллекции.
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');
// Получить конкретную собаку по IDconst poodleData = await getEntry('dogs', 'poodle');Порядок записей в коллекциях не гарантирован. Если вам нужна сортировка (например, по дате), её нужно выполнить вручную с помощью метода .sort().
Использование в шаблонах
Заголовок раздела «Использование в шаблонах»Вы можете использовать данные коллекций прямо в компонентах 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/, поэтому маршруты для них не создаются автоматически. Вам нужно создать динамический маршрут для генерации страниц.
Статическая генерация (SSG)
Заголовок раздела «Статическая генерация (SSG)»Используйте getStaticPaths() для создания страниц во время сборки:
---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)
Заголовок раздела «Серверный рендеринг (SSR)»В режиме SSR страницы генерируются по запросу:
---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).