Макросы и преобразования

Основы макросов в MDX

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

Синтаксис макросов в MDX может быть реализован через функции, экспортируемые из внешних файлов:

// macros.js
export function Highlight({ children, color = 'yellow' }) {
  return <span style={{ backgroundColor: color }}>{children}</span>;
}

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

import { Highlight } from './macros'

Это пример текста с <Highlight color="lightgreen">выделением</Highlight>.

Ключевой момент: макросы обрабатываются как обычные React-компоненты, но позволяют внедрять стилизованные и динамичные фрагменты Markdown без лишнего кода.


Преобразования контента

MDX позволяет применять преобразования к содержимому через Remark-плагины и Rehype-плагины, что обеспечивает гибкую трансформацию Markdown перед рендерингом в JSX.

Remark-плагины

Remark работает на уровне синтаксического дерева Markdown (MDAST), позволяя:

  • Автоматически генерировать заголовки и якоря.
  • Преобразовывать специальные синтаксические конструкции в React-компоненты.
  • Выполнять анализ и модификацию текста до передачи его в JSX.

Пример подключения плагина для добавления нумерации заголовков:

import remarkSlug from 'remark-slug';
import remarkAutolinkHeadings from 'remark-autolink-headings';

const mdxOptions = {
  remarkPlugins: [remarkSlug, remarkAutolinkHeadings],
};
Rehype-плагины

Rehype работает на уровне HTML-дерева (HAST), что позволяет:

  • Добавлять классы и атрибуты к элементам.
  • Преобразовывать изображения в оптимизированные компоненты.
  • Обрабатывать ссылки и списки для улучшенной семантики.

Пример применения Rehype-плагина для автоматического добавления target="_blank" к внешним ссылкам:

import rehypeExternalLinks from 'rehype-external-links';

const mdxOptions = {
  rehypePlugins: [[rehypeExternalLinks, { target: '_blank', rel: ['noopener'] }]],
};

Создание пользовательских макросов с преобразованиями

MDX поддерживает комбинацию макросов и плагинов для сложных трансформаций. Например, можно создать макрос, который автоматически оборачивает блоки кода в компонент с подсветкой синтаксиса:

// CodeBlock.js
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { dark } from 'react-syntax-highlighter/dist/esm/styles/prism';

export default function CodeBlock({ className, children }) {
  const language = className?.replace('language-', '') || 'text';
  return <SyntaxHighlighter language={language} style={dark}>{children}</SyntaxHighlighter>;
}

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

import CodeBlock from './CodeBlock'

<CodeBlock className="language-js">
{`console.log("Hello, MDX!");`}
</CodeBlock>

Эта комбинация позволяет:

  • Автоматически преобразовывать любой блок кода в красиво оформленный компонент.
  • Поддерживать повторное использование макроса в разных документах.
  • Поддерживать интеграцию с Remark/Rehype для дальнейшей оптимизации.

Динамическое создание макросов

MDX позволяет создавать макросы не только как отдельные компоненты, но и как функции, возвращающие JSX на основе параметров. Это открывает возможности для генерации сложного контента на лету:

export function Alert({ type = 'info', children }) {
  const colors = { info: 'blue', warning: 'orange', error: 'red' };
  return <div style={{ borderLeft: `4px solid ${colors[type]}`, padding: '10px' }}>{children}</div>;
}

Применение:

<Alert type="warning">Это предупреждение!</Alert>

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


Взаимодействие макросов с MDXProvider

MDXProvider позволяет глобально переопределять стандартные Markdown-элементы. В сочетании с макросами это дает мощный инструмент для унификации стиля:

import { MDXProvider } from '@mdx-js/react';
import { Highlight, CodeBlock } from './macros';

const components = {
  h1: (props) => <h1 style={{ color: 'darkblue' }} {...props} />,
  code: CodeBlock,
  span: Highlight
};

<MDXProvider components={components}>
  <MDXContent />
</MDXProvider>

Преимущества:

  • Все h1, code и span в документации автоматически получают единый стиль.
  • Можно комбинировать с Remark/Rehype для глобальных преобразований.
  • Позволяет создавать библиотеку макросов и компонентов для всей документации.

Советы по организации макросов и преобразований

  • Разделять логические блоки макросов по функциональности: визуальные, интерактивные, утилитарные.
  • Использовать плагины для стандартизации Markdown: заголовки, ссылки, таблицы.
  • Инкапсулировать преобразования внутри макросов, чтобы минимизировать зависимости от внешних плагинов.
  • Создавать унифицированный файл импорта макросов для всех MDX-документов проекта.

Эти подходы обеспечивают масштабируемость, поддерживаемость и удобство сопровождения большого объема документации или учебного контента.