Перейти к содержанию

Markdown и контракт коллекции

Подготовленный проект пока содержит только главную страницу. Добавим пять Markdown-материалов и определим, какие данные должна иметь каждая запись. В Astro коллекция соединяет источник файлов и схему их метаданных. Она не является оглавлением, которое нужно вручную переписывать при добавлении статьи. Цель этапа — получить единый контракт содержания для дальнейших маршрутов и списков.

Файл src/content.config.ts экспортирует объект collections с коллекцией lessons. Loader glob читает Markdown из src/data/lessons. Явная базовая папка помогает отделить материалы от страниц-компонентов. Файл статьи не требуется положить в src/pages, чтобы он стал доступным коллекции. И наоборот, наличие записи ещё не создаёт ей публичный маршрут: это следующая отдельная задача.

Коллекция как договор редакции

Схема импортирует Zod через astro/zod, как предусмотрено актуальной документацией. Исторические примеры с другим импортом не следует переносить механически в закреплённый профиль. Название, описание, тема, порядок и статус черновика получают конкретные типы. Схема объясняет не только редактору, но и сборщику, каких данных можно ожидать от записи.

Тема допускает только content или interface. Это маленький словарь учебного проекта. Если случайно написать contents, запись не должна молча образовать новую ветку. Для реальной библиотеки перечень тем лучше связать с общей структурой каталога. В этой серии ограниченный набор позволяет увидеть ошибку без загрузки всех разделов ProfessorWeb.

order является целым неотрицательным числом. Он задаёт учебную последовательность, а не дату публикации и не уникальность адреса. Два материала могут иметь одинаковый порядок, поэтому позднее добавим устойчивое второе условие сортировки. Само наличие order не создаёт кнопки предыдущего и следующего урока. Эти связи нужно сформировать по той же выборке.

draft по умолчанию равен true. Безопасное начальное состояние новой записи — редакционный черновик. Пять учебных материалов явно получают false, чтобы демонстрировать публичную выборку внутри будущего локального приложения. Этот статус относится к примеру «Полка» и не меняет draft: true у самих статей курса в ProfessorWeb.

ID записи получается из имени файла loader. В нашем наборе это markdown, navigation, urls, assets, forms. ID нужен для обращения к данным; он ещё не является непреложным старым адресом сайта. Отделение этих понятий пригодится при сохранении PHP-путей. Переименование файла может изменить ID и связи, поэтому его не следует считать только косметическим действием.

Содержание Markdown имеет вводный абзац и два заголовка второго уровня. Первый уровень будет формировать шаблон из title. Если добавить H1 в тело, будущая статья получит повторный основной заголовок. Пока набор намеренно короткий: урок посвящён контракту записей, а не написанию пяти полноценных статей для настоящего сайта.

Ожидаемое состояние — loader видит пять записей, каждая соответствует схеме. Это описание будущей подготовки, не полученный лог выполнения. Для самостоятельного опыта измените одну тему или уберите обязательное описание и рассмотрите сообщение среды, затем верните правильные данные. Главное — понять, что ошибка содержания должна быть выявлена до выдачи страницы посетителю.

Полный файл src/content.config.ts текущего этапа:

import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
const lessons = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/data/lessons' }),
  schema: z.object({
    title: z.string().min(1), description: z.string().min(1),
    topic: z.enum(['content', 'interface']), order: z.number().int().nonnegative(),
    draft: z.boolean().default(true),
  }),
});
export const collections = { lessons };

Полный файл src/data/lessons/markdown.md текущего этапа:

---
title: "Markdown и содержание"
description: "Учебный материал: markdown и содержание."
topic: content
order: 1
draft: false
---

Первый абзац объясняет назначение материала «Markdown и содержание».

## Исходные данные

Библиотека хранит содержание отдельно от шаблонов. У каждой записи есть название, тема и порядок.

## Изменение примера

Меняйте один признак за раз и сравнивайте получившуюся страницу с исходным состоянием.

Полный файл src/data/lessons/navigation.md текущего этапа:

---
title: "Навигация каталога"
description: "Учебный материал: навигация каталога."
topic: interface
order: 2
draft: false
---

Первый абзац объясняет назначение материала «Навигация каталога».

## Исходные данные

Библиотека хранит содержание отдельно от шаблонов. У каждой записи есть название, тема и порядок.

## Изменение примера

Меняйте один признак за раз и сравнивайте получившуюся страницу с исходным состоянием.

Разбор состояния библиотеки

Схема описывает форму данных, но не все требования хорошего текста. Строка title длиной в один символ формально удовлетворяет минимальному ограничению, хотя может ничего не объяснять. Поэтому валидация и редакционная оценка имеют разные роли. Первая предотвращает неправильный тип или неизвестную тему; вторая рассматривает ясность, содержание и место урока в серии. Не нужно пытаться заменить преподавательский разбор одним регулярным выражением.

Порядок файлов на диске также не является учебным порядком. Имена вроде assets и forms удобны как ключи, но алфавитная сортировка поставила бы их раньше введения Markdown. Именно поле order сохраняет выбранные предпосылки. При росте библиотеки полезно сначала определить результаты каждого урока, затем назначить порядок. Числа не создают эту педагогическую связь сами по себе.

У коллекции нет необходимости хранить HTML-оболочку внутри каждой записи. Markdown содержит основное объяснение, а layout добавит хедер и футер позднее. Если скопировать весь старый документ в тело Markdown, результат может получить вложенные html и body, повторную навигацию и конфликтующие стили. Импорт исторического материала требует отдельного очищения и сохранения URL, а не простой замены расширения файла.

Для самостоятельного варианта добавьте шестую запись с допустимой темой, порядком шесть и draft true. Сейчас её наличие важно только для loader и схемы. В следующих шагах она должна остаться вне публичного набора. Затем намеренно поменяйте order на строку. Рассмотрите, какое правило сообщает о проблеме, и верните числовой тип. Не исправляйте ошибку удалением проверки, если данные действительно нарушают договор.

Значение description используется в нескольких представлениях: карточке, метаданных и будущем индексе поиска. Оно должно быть пригодно для самостоятельного чтения без всего тела статьи. Хорошее описание называет действие или изучаемую связь. Не помещайте туда HTML-обёртку и не рассчитывайте, что каждый потребитель будет разбирать её одинаково. Строковые метаданные сохраняют ясную границу между содержанием и шаблоном.

Если часть данных приходит из CMS, концепция коллекции остаётся полезной, но loader может измениться. Это не означает, что локальный glob умеет запрашивать любой внешний сервис. В данном уроке источник ограничен файлами проекта. Подключение сети добавит правила актуальности, ошибок и возможных секретов, которые требуется изучать отдельно. Такое ограничение делает первый контракт воспроизводимым и достаточно небольшим.

Значение draft относится к нашей схеме данных. Astro не обязан исключать его из любой пользовательской страницы автоматически. Следующий маршрут и общий helper выполнят явную фильтрацию. Поэтому при будущем рефакторинге нельзя удалить predicate с аргументом, что статус уже существует в Markdown. Метаданные описывают намерение, а каждый канал вывода должен применять соответствующий договор. Это различие пригодится и для поиска, и для карты.

Условия для самостоятельного наблюдения

Это план будущего разбора, а не журнал выполненных проверок. Рассмотрите одинаковые исходные данные и сопоставьте действие с ожидаемым состоянием.

Условие Ожидаемое состояние и его граница
Правильная тема Одна из двух разрешённых тем сохраняет согласованную будущую группировку.
Опечатка в теме Схема должна остановить некорректное значение, а не создать скрытое новое название раздела.
Нет draft Запись получает консервативное состояние черновика по умолчанию.
Дробный order Учебный договор требует целое число, дробь не является разрешённой последовательностью.
Переименован файл ID записи может измениться, поэтому необходимо пересмотреть зависимые связи.
Есть тело Markdown Наличие данных не создаёт самостоятельный URL без страницы-маршрута.

Оглавление серии, курсы ProfessorWeb и полный архив исходников. Для этого урока выберите lesson-02.

Первичные источники: Collections.

Редакционный статус: локальный черновик. Установка, учебные программы, браузерные сценарии, тесты и публикация не выполнялись. Описанные эффекты ожидаемые.