Блог на MDX

MDX — это расширение Markdown, которое позволяет включать JSX-компоненты прямо в тексты. В отличие от стандартного Markdown, MDX превращает статический контент в интерактивный, динамически управляемый через React-компоненты.

import { MyButton } from './components/MyButton.mdx';

export default function BlogPost() {
  return (
    <div>
      <h1>Заголовок статьи</h1>
      <p>Простой текст с возможностью вставки компонента:</p>
      <MyButton>Нажми меня</MyButton>
    </div>
  );
}

Интеграция компонентов в MDX

MDX позволяет импортировать React-компоненты и использовать их как часть разметки. Любой компонент можно вставить с использованием стандартного синтаксиса JSX:

import Alert from './components/Alert';

# Новость дня

<Alert type="warning">
  Важное уведомление для всех пользователей!
</Alert>

Текст статьи продолжается после компонента.

Ключевой момент: MDX компилируется в React-компоненты, поэтому можно использовать все возможности JSX: условные рендеринги, циклы, пропсы, стили и контекст.

Структура проекта на MDX

Для создания блога на MDX обычно используют следующую структуру:

/src
  /posts
    first-post.mdx
    second-post.mdx
  /components
    Layout.js
    Header.js
    Footer.js
/pages
  index.js
  [slug].js
  • posts — директория для всех статей в формате .mdx.
  • components — набор React-компонентов, которые можно использовать внутри MDX.
  • pages — маршрутизация Next.js (или другого фреймворка) для рендеринга статей.

Загрузка и отображение MDX-файлов

Для динамического отображения статей в блоге на Next.js или Remix необходимо:

  1. Установить @next/mdx или @mdx-js/react.
  2. Настроить поддержку MDX в конфигурации.
  3. Импортировать MDX-файл как компонент.

Пример загрузки MDX-файла в Next.js:

import { MDXRemote } from 'next-mdx-remote';
import { serialize } from 'next-mdx-remote/serialize';
import fs from 'fs';
import path from 'path';

export default function Post({ source }) {
  return <MDXRemote {...source} />;
}

export async function getStaticProps() {
  const filePath = path.join(process.cwd(), 'src/posts/first-post.mdx');
  const fileContent = fs.readFileSync(filePath, 'utf8');
  const mdxSource = await serialize(fileContent);
  
  return { props: { source: mdxSource } };
}

Настройка компонентов через MDXProvider

MDXProvider позволяет определять, как будут отображаться стандартные элементы Markdown. Например, можно изменить визуальное оформление заголовков, параграфов и ссылок:

import { MDXProvider } from '@mdx-js/react';
import CustomH1 from './components/CustomH1';
import CustomLink from './components/CustomLink';

const components = {
  h1: CustomH1,
  a: CustomLink,
};

export default function App({ children }) {
  return <MDXProvider components={components}>{children}</MDXProvider>;
}

Это особенно полезно для единого стиля блога, где каждый заголовок и ссылка имеют фирменный дизайн.

Использование пропсов и динамических данных

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

<MyWidget user={user} showDetails={true} />

В этом примере user передается из React-компонента, а MDX используется для рендеринга динамического контента.

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

MDX сохраняет все преимущества Markdown:

  • Заголовки (#, ##, ###)
  • Списки (-, *, 1.)
  • Кодовые блоки с подсветкой
  • Таблицы и блоки цитат

При этом любой Markdown-элемент можно заменить на кастомный React-компонент через MDXProvider.

Оптимизация производительности

Для больших блогов рекомендуется:

  • Использовать next-mdx-remote для динамической загрузки статей.
  • Компилировать MDX на этапе сборки (getStaticProps или getStaticPaths), чтобы уменьшить нагрузку на клиент.
  • Разделять компоненты на маленькие, переиспользуемые элементы.

Примеры интерактивных элементов

  • Вставка графиков и диаграмм через компоненты Chart.js или Recharts.
  • Формы обратной связи с валидацией через React Hook Form.
  • Встроенные видео и галереи изображений.
<Gallery images={['img1.png', 'img2.png']} />
<Video src="intro.mp4" />

Обработка маршрутов и SEO

MDX отлично интегрируется с Next.js для генерации статических страниц. Можно автоматически строить SEO-мета-теги:

export async function getStaticPaths() {
  const posts = ['first-post', 'second-post'];
  const paths = posts.map(slug => ({ params: { slug } }));
  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const filePath = `src/posts/${params.slug}.mdx`;
  const fileContent = fs.readFileSync(filePath, 'utf8');
  const mdxSource = await serialize(fileContent);
  return { props: { source: mdxSource } };
}

Каждая статья становится отдельной страницей с собственным маршрутом и метаданными для поисковых систем.

Резюме по архитектуре MDX-блога

  • Контент: хранится в .mdx файлах.
  • Компоненты: React-компоненты для интерактивного контента.
  • Рендеринг: через MDXProvider и MDXRemote.
  • Маршрутизация: статические или динамические страницы через Next.js.
  • SEO и оптимизация: статическая генерация, кастомные мета-теги, минимизация клиентских вычислений.

Такой подход позволяет создавать гибкий, расширяемый блог с интерактивными элементами и единым дизайном.