Блог (MDX + RSS)
Блог на MDX-файлах: посты лежат в content/blog/*.mdx с YAML-фронтматтером, страница списка и
страница поста генерируются статически, есть валидный RSS-фид на /rss.xml.
Из чего состоит
| Файл | Назначение |
|---|---|
content/blog/*.mdx | Посты с фронтматтером title, date, description, slug. |
src/lib/blog/posts.ts | Чтение/валидация постов (gray-matter + Zod): getAllPosts, getPostBySlug, getAllPostSlugs. |
src/lib/blog/rss.ts | Генерация RSS 2.0 (buildRssXml) с экранированием XML. |
src/app/[locale]/blog/page.tsx | Список постов (/blog, /en/blog). |
src/app/[locale]/blog/[slug]/page.tsx | Страница поста, рендер MDX через next-mdx-remote/rsc. |
src/app/rss.xml/route.ts | RSS-фид на /rss.xml. |
Фронтматтер поста
---
title: Заголовок поста
date: 2026-06-01
description: Короткое описание для списка, SEO и RSS.
slug: url-slug
---
# Обычный Markdown/MDX
Тело поста…
Если slug не указан, используется имя файла без расширения. Дата в YAML может быть без кавычек
(2026-06-01) — она нормализуется в строку YYYY-MM-DD.
Добавить пост
- Создайте
content/blog/my-post.mdxс фронтматтером. - Готово — пост появится в
/blog, на своей странице/blog/my-postи в/rss.xml(список отсортирован по дате, новые сверху). Slug'и статически пре-рендерятся черезgenerateStaticParams, поэтому чтения файлов в рантайме нет.
RSS-фид
/rss.xml (src/app/rss.xml/route.ts) отдаёт валидный RSS 2.0 (content-type: application/rss+xml), построенный чистой функцией buildRssXml: канал с title / link /
description, atom:link на себя и по <item> на каждый пост (title, link, guid, pubDate,
description) со спецсимволами, экранированными в XML. Фид вычисляется на этапе сборки
(force-static), так что в рантайме доступа к файловой системе нет.
Подсветка синтаксиса (опционально)
Базовый рендер MDX включён без подсветки. Чтобы добавить её, подключите rehype-плагин
(rehype-pretty-code / rehype-highlight) в options.mdxOptions.rehypePlugins компонента
MDXRemote в src/app/[locale]/blog/[slug]/page.tsx.
Дальше
- SEO и метаданные — посты блога попадают в
sitemap.xml, а страница поста задаёт своиtitle/description.