HOWTO: Публикация статей в блоге — Блог
$ cat example/howto.md

HOWTO: Публикация статей в блоге

HOWTO: Публикация статей в блоге

Полное руководство по добавлению контента: от простого Markdown до интерактивных MDX-компонентов.


1. Что такое MDX — краткая история

Markdown (2004) — Джон Грубер создал лёгкий язык разметки, который читается как обычный текст. Идеален для статей, но ограничен: только текст, заголовки, списки и ссылки.

MDX (2018) — команда Vercel (создатели Next.js) расширила Markdown, добавив возможность вставлять JSX-компоненты прямо в текст. Это изменило правила игры:

Markdown  →  только текст и разметка
MDX       →  текст + компоненты + интерактивность

Зачем это нужно:

  • Вставить интерактивный график прямо в статью
  • Добавить код с возможностью запуска
  • Встроить видео, аудио, твиты, карточки
  • Создать свои компоненты (калькулятор, демо, опрос)

Кто использует: Vercel, Stripe, GitHub Docs, Shopify, Tailwind CSS, MDX — индустриальный стандарт для технической документации.


2. Структура контента

Все статьи хранятся в src/content/blog/. Поддерживаются два формата:

ФорматРасширениеКогда использовать
Markdown.mdПростые текстовые статьи, заметки, HOWTO
MDX.mdxСтатьи с компонентами, демо, интерактивом
src/content/blog/
├── open-source-ai-2024.md          # Обычная статья (текст + код)
├── git-methodologies.md            # Обычная статья
├── top-5-dev-tools.md              # Обычная статья
├── example/
│   ├── article-template.md         # Шаблон Markdown
│   ├── example-article.mdx         # MDX статья (сравнение)
│   └── HOWTO.md                    # Эта инструкция
└── (ваша статья).md / .mdx         # ← Сюда добавляйте новое

Как добавить новую статью

Вариант 1 — Просто скопировать файл:

copy src\content\blog\example\article-template.md src\content\blog\novaya-statya.md

Вариант 2 — Создать с нуля:

# Создать файл
type nul > src\content\blog\novaya-statya.md

# Открыть в редакторе
code src\content\blog\novaya-statya.md

Вариант 3 — В подпапке (для организации):

mkdir src\content\blog\ai
copy src\content\blog\example\article-template.md src\content\blog\ai\pro-ai.md

[!TIP] Имя файла станет частью URL: novaya-statya.md/blog/novaya-statya/ Подпапки тоже учитываются: ai/pro-ai.md/blog/ai-pro-ai/


3. Обязательный фронтматтер

Каждая статья начинается с YAML-блока:

---
title: 'Заголовок статьи'
description: 'Краткое описание для SEO и карточки (1-2 предложения)'
date: 2026-04-12
tags: ['Тег1', 'Тег2']
image: '/images/preview.jpg'  # опционально
draft: false                   # true = скрыть из публикации
---

Без этих полей статья не появится на сайте!


4. Markdown — основы

Текст и разметка

# Заголовок 1
## Заголовок 2
### Заголовок 3

**Жирный текст** и *курсив*

- Пункт списка
- Ещё пункт
  - Вложенный пункт

1. Нумерованный список
2. Второй пункт

> Цитата или заметка

[Ссылка](https://example.com)

![Картинка](/images/photo.jpg)

Блоки кода

```bash
npm run dev
```

```python
def hello():
    print("Привет, мир!")
```

```typescript
const x: number = 42;
```

Поддерживаемые языки: bash, python, typescript, javascript, go, rust, java, c, sql, json, yaml, css, html, dockerfile и другие.

Таблицы

| Колонка 1 | Колонка 2 | Колонка 3 |
|-----------|-----------|-----------|
| Данные 1  | Данные 2  | Данные 3  |

5. MDX — компоненты и интерактив

MDX = Markdown + JSX. Вы можете импортировать компоненты и использовать их как теги.

Импорт компонентов

---
title: 'Статья с компонентами'
description: 'Пример MDX'
date: 2026-04-12
tags: ['MDX']
---

import { Callout } from '../../../components/Callout.astro';

# Заголовок статьи

<Callout type="info">
Это информационный блок!
</Callout>

Обычный текст статьи...

Доступные компоненты

КомпонентОписаниеПример
<Callout>Блок-заметка<Callout type="info">Текст</Callout>

Типы Callout:

  • type="info" — ℹ️ информация (синий)
  • type="warning" — ⚠️ предупреждение (жёлтый)
  • type="tip" — 💡 совет (зелёный)

6. Медиа в Markdown и MDX

Изображения

<!-- Из public/images/ -->
![Описание](/images/screenshot.png)

<!-- С размерами -->
![Описание](/images/screenshot.png "Заголовок")

Видео

<!-- Встроенное YouTube -->
<iframe width="560" height="315" src="https://www.youtube.com/embed/VIDEO_ID" frameborder="0" allowfullscreen></iframe>

<!-- Локальное видео (положите в public/) -->
<video controls width="100%">
  <source src="/videos/demo.mp4" type="video/mp4">
  Ваш браузер не поддерживаетет видео.
</video>

Аудио

<!-- Встроенный аудио -->
<audio controls>
  <source src="/audio/podcast.mp3" type="audio/mpeg">
  Ваш браузер не поддерживаетет аудио.
</audio>

Интерактивные элементы

MDX позволяет создавать полноценные интерактивные компоненты:

---
title: 'Интерактивная статья'
description: 'Пример'
date: 2026-04-12
tags: ['MDX', 'Интерактив']
---

import { Counter } from '../../../components/Counter.astro';

# Интерактивный счётчик

Нажмите кнопку:

<Counter />

Примеры интерактивных компонентов, которые можно создать:

ТипОписаниеПример
СчётчикКнопка + состояние<Counter />
ТабыПереключение вкладок<Tabs><Tab title="Код">...</Tab></Tabs>
ОпросГолосование в статье<Poll question="..." options={['Да', 'Нет']} />
КалькуляторВычисления<Calculator formula="..." />
ТерминалИнтерактивная консоль<Terminal command="npm install" />
КарточкаИнформационный блок<Card title="..." icon="🚀">...</Card>
АккордеонРаскрывающийся блок<Accordion title="FAQ">...</Accordion>
СлайдерГалерея изображений<Slider images={['/img/1.jpg', ...]} />
ГрафикВизуализация данных<Chart data={[...]} type="bar" />

Пример: компонент-аккордеон

<!-- src/components/Accordion.astro -->
<details class="my-4 p-4 border rounded-lg">
  <summary class="cursor-pointer font-bold text-[var(--text-primary)]">
    <slot name="title" />
  </summary>
  <div class="mt-3 text-[var(--text-secondary)]">
    <slot />
  </div>
</details>

Использование в MDX:

import { Accordion } from '../../../components/Accordion.astro';

<Accordion>
  <span slot="title">Как добавить статью?</span>
  Просто создайте .md или .mdx файл в src/content/blog/
</Accordion>

7. Создание собственного компонента

Шаг 1: Создать файл компонента

<!-- src/components/MyComponent.astro -->
---
interface Props {
  title?: string;
}

const { title = 'Заголовок' } = Astro.props;
---

<div class="my-6 p-6 bg-[var(--bg-secondary)] rounded-lg border border-[var(--border-color)]">
  <h3 class="text-xl font-bold mb-3 font-mono text-[var(--accent-color)]">{title}</h3>
  <div class="text-[var(--text-secondary)]">
    <slot />
  </div>
</div>

Шаг 2: Импортировать в MDX

---
title: 'Статья с моим компонентом'
description: 'Пример'
date: 2026-04-12
tags: ['MDX']
---

import { MyComponent } from '../../../components/MyComponent.astro';

# Заголовок

<MyComponent title="Мой блок">
  Здесь любой контент, включая **Markdown**!
</MyComponent>

8. Быстрый старт (копирование шаблона)

# Скопировать Markdown-шаблон
copy src\content\blog\example\article-template.md src\content\blog\novaya-statya.md

# Скопировать MDX-шаблон
copy src\content\blog\example\example-article.mdx src\content\blog\mdx-statya.mdx

# Открыть для редактирования
code src\content\blog\novaya-statya.md

9. Чек-лист перед публикацией

  • Фронтматтер заполнен (title, description, date)
  • Теги указаны (для фильтрации)
  • Код работает (проверить блоки кода)
  • Ссылки корректны (проверить URL)
  • draft: false (или удалить поле)
  • blog build прошёл без ошибок
  • blog start — статья видна на сайте
  • (MDX) Импорт компонентов после фронтматтера
  • (MDX) Все JSX-теги закрыты
  • (MDX) Путь к компоненту: ../../../components/Имя.astro

10. Команды CLI

КомандаОписание
blog startЗапустить dev-сервер
blog stopОстановить сервер
blog statusПроверить статус
blog buildСобрать проект
blog openОткрыть в браузере
blog restartПерезапустить сервер

11. Решение проблем

Статья не появляется на сайте

  1. Проверьте draft: false
  2. Проверьте фронтматтер — все обязательные поля
  3. Запустите blog build — будут ошибки валидации

Ошибка валидации

data does not match collection schema

Проверьте типы полей:

  • date — формат YYYY-MM-DD
  • tags — массив ['Тег1', 'Тег2']
  • title, description — строки

MDX не компилируется

  • Импорт компонентов после фронтматтера
  • Путь к компоненту: ../../../components/Имя.astro
  • JSX-теги должны быть закрыты
  • Проверьте, что pattern: '**/*.{md,mdx}' в src/content.config.ts

Пустая страница статьи

Убедитесь, что в src/pages/blog/[slug].astro используется:

import { getCollection, render } from 'astro:content';
const { Content } = await render(post);
<Content />

12. Примеры файлов

Смотрите в папке example/:

ФайлТипОписание
article-template.mdMarkdownШаблон с разметкой, кодом, таблицами
example-article.mdxMDXСтатья-сравнение с таблицами и кодом
HOWTO.mdMarkdownЭта инструкция

13. Полезные ссылки