Архитектура плагинов MDX

MDX — это расширение Markdown, позволяющее интегрировать JSX прямо в Markdown-документы. Архитектура MDX построена на модульной системе обработки контента, где ключевую роль играют плагины. Плагины обеспечивают возможность расширения функциональности на каждом этапе компиляции: от синтаксического анализа до генерации конечного JavaScript-кода.

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


Плагины для парсинга

На этом этапе происходит чтение исходного Markdown/MDX-кода и преобразование его в AST (Abstract Syntax Tree). MDX использует систему парсеров из экосистемы remark и rehype:

  • remark-плагины обрабатывают Markdown-структуры: заголовки, списки, цитаты, таблицы.
  • rehype-плагины работают с HTML-структурами, которые могут появляться внутри MDX-документа.

Основная задача парсера — создать корректное дерево синтаксических элементов, которое затем передается на этап трансформации.

Пример подключения плагина для remark:

import { compile } from '@mdx-js/mdx';
import remarkGfm from 'remark-gfm';

const mdxContent = `
# Заголовок
- Список
`;

const result = await compile(mdxContent, {
  remarkPlugins: [remarkGfm],
});

remarkGfm добавляет поддержку расширений GitHub Flavored Markdown (GFM) — таблицы, зачеркивания, задачи.


Плагины для трансформации

После построения AST применяется этап трансформации. Здесь rehype-плагины и некоторые специализированные MDX-плагины могут изменять дерево. Возможные операции включают:

  • Преобразование нестандартных синтаксических конструкций в стандартные JSX-компоненты.
  • Инъекцию дополнительных атрибутов и классов к элементам.
  • Оптимизацию структуры AST для дальнейшей компиляции.

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

import rehypePlugin from 'rehype';

function addParagraphClass() {
  return (tree) => {
    visit(tree, 'element', (node) => {
      if (node.tagName === 'p') {
        node.properties = node.properties || {};
        node.properties.className = ['custom-paragraph'];
      }
    });
  };
}

Здесь используется visit из библиотеки unist-util-visit, чтобы обойти дерево и применить изменения к нужным элементам.


Плагины для компиляции

На последнем этапе MDX-трансформированное дерево AST конвертируется в JavaScript/JSX-код. Компиляторы MDX используют плагины для:

  • Генерации корректных JSX-компонентов для React.
  • Подключения импортов внешних компонентов.
  • Интеграции с системами маршрутизации и SSR (Server-Side Rendering).

Пример добавления глобального импорта через плагин:

import { compile } from '@mdx-js/mdx';

const result = await compile(mdxContent, {
  providerImportSource: '@mdx-js/react',
  remarkPlugins: [],
  rehypePlugins: [],
});

Параметр providerImportSource автоматически добавляет импорт MDXProvider, который позволяет использовать собственные компоненты для тегов Markdown.


Особенности построения плагинов

  1. Композиция: Плагины можно комбинировать, выстраивая цепочки обработки. Порядок важен, так как один плагин может менять структуру AST, влияя на работу последующих.
  2. Асинхронность: Современные плагины MDX поддерживают асинхронные операции, например загрузку внешних данных.
  3. Совместимость с remark/rehype: Многие плагины создаются для экосистемы unified, поэтому их можно использовать без модификаций.
  4. Трансформация JSX: Плагины могут работать не только с Markdown-узлами, но и с JSX-узлами внутри MDX, что позволяет внедрять сложные UI-компоненты.

Структура типичного плагина

MDX-плагин — это функция, принимающая AST и опции и возвращающая изменённое дерево:

function myMdxPlugin(options = {}) {
  return (tree, file) => {
    // Пример: добавить атрибут data-type ко всем заголовкам h2
    visit(tree, 'element', (node) => {
      if (node.tagName === 'h2') {
        node.properties = node.properties || {};
        node.properties['data-type'] = options.type || 'default';
      }
    });
  };
}

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


Взаимодействие плагинов на практике

Плагины работают по принципу цепочки обработки:

  1. Markdown → remark-плагины → AST.
  2. AST → rehype-плагины → модифицированное AST.
  3. AST → MDX-компилятор → JSX-код.

Такое разделение позволяет:

  • Легко заменять шаги обработки.
  • Внедрять новые функции без переписывания ядра MDX.
  • Использовать существующие плагины unified для Markdown и HTML.