MDX предоставляет гибкий механизм расширения функциональности через
плагины, которые позволяют модифицировать процесс
разбора Markdown, добавлять новые синтаксические конструкции и
интегрировать React-компоненты на уровне AST (Abstract Syntax Tree).
Плагины работают на этапе компиляции MDX в JavaScript и могут быть
встроены как в конфигурацию сборщика, так и напрямую через API
@mdx-js/mdx.
Плагин в MDX обычно представляет собой функцию, которая получает на вход AST дерева Markdown и объект с настройками. Основные элементы структуры:
function myPlugin(options = {}) {
return (tree, vfile) => {
// Логика обработки AST
};
}
Remark-плагины Работают с AST Markdown до того, как содержимое превратится в JSX. Позволяют добавлять новые синтаксические конструкции, модифицировать текст, внедрять теги или метаданные.
Rehype-плагины Работают на уровне HTML-дерева после трансформации Markdown в HTML. Используются для добавления атрибутов, изменения структуры HTML или интеграции с внешними библиотеками.
AST представляет документ в виде дерева узлов. Каждый узел имеет свойства:
type — тип узла (paragraph,
heading, text, link,
code и т.д.).children — массив дочерних узлов.value — текстовое содержимое узла (для узлов типа
text).data — дополнительная информация, которую можно
использовать для плагина.Пример обхода дерева:
function myPlugin() {
return (tree) => {
visit(tree, 'text', (node) => {
if (node.value.includes('TODO')) {
node.value = node.value.replace(/TODO/g, '⚠️');
}
});
};
}
Здесь используется метод visit из пакета
unist-util-visit, позволяющий рекурсивно обходить AST и
модифицировать узлы.
MDX позволяет интегрировать React-компоненты в Markdown. Плагин может автоматически оборачивать определённые слова или конструкции в компонент.
import { visit } from 'unist-util-visit';
function highlightPlugin({ componentName = 'Highlight' } = {}) {
return (tree) => {
visit(tree, 'text', (node, index, parent) => {
if (!node.value.includes('important')) return;
const parts = node.value.split(/(important)/);
const newNodes = parts.map((part) => {
if (part === 'important') {
return {
type: 'mdxJsxFlowElement',
name: componentName,
attributes: [],
children: [{ type: 'text', value: part }],
};
}
return { type: 'text', value: part };
});
parent.children.splice(index, 1, ...newNodes);
});
};
}
Результатом работы будет автоматическое преобразование слова
important в JSX-компонент
<Highlight>.
Плагины MDX поддерживают конфигурацию через объект настроек:
import { compile } from '@mdx-js/mdx';
import highlightPlugin from './highlightPlugin.js';
const mdxContent = `
Это очень important текст.
`;
const result = await compile(mdxContent, {
remarkPlugins: [[highlightPlugin, { componentName: 'CustomHighlight' }]],
});
Такой подход позволяет создавать универсальные плагины, которые легко настраиваются под разные проекты.
MDX поддерживает возможность выдачи предупреждений через
vfile:
function todoWarningPlugin() {
return (tree, vfile) => {
visit(tree, 'text', (node) => {
if (node.value.includes('TODO')) {
vfile.warn('Найдена метка TODO', node);
}
});
};
}
vfile.warn(message, node) — добавляет предупреждение с
привязкой к конкретному узлу.vfile.fail(message, node) — генерирует ошибку, прерывая
компиляцию.MDX-плагины могут использоваться с:
@mdx-js/rollup или
vite-plugin-mdx.@mdx-js/loader.@next/mdx.Подключение выглядит одинаково: передача плагина в
remarkPlugins или rehypePlugins в
конфигурации.
import { MDXProvider } from '@mdx-js/react';
import highlightPlugin from './highlightPlugin.js';
const mdxComponents = {
Highlight: ({ children }) => <mark>{children}</mark>,
};
<MDXProvider components={mdxComponents}>
<MDXContent />
</MDXProvider>
unist-util-visit и
unist-util-visit-parents для безопасного обхода
дерева.vfile.warn вместо
прямого изменения текста, если нужно уведомить пользователя.Этот подход позволяет создавать мощные и расширяемые плагины для MDX, полностью контролируя процесс компиляции Markdown и интеграцию с React-компонентами.