Провайдеры компонентов

В экосистеме Remark и Rehype провайдеры компонентов играют ключевую роль в гибкой трансформации Markdown и HTML-структур. Они позволяют не только управлять парсингом и обработкой узлов дерева, но и внедрять собственные компоненты для рендеринга контента.


Основы работы с провайдерами компонентов

Провайдер компонента — это объект или функция, которая сообщает движку обработки, как рендерить определённый узел в AST (Abstract Syntax Tree). В контексте Remark и Rehype это может быть:

  • Markdown-узел (paragraph, heading, link и др.)
  • HTML-узел (div, span, a и др.)

Принцип работы:

  1. Идентификация узла по типу.
  2. Применение кастомного компонента вместо стандартного рендера.
  3. Передача контекста и свойств компоненту.

Пример простого провайдера в Rehype:

import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeReact from 'rehype-react';
import React from 'react';
import ReactDOM from 'react-dom';

const components = {
  h1: (props) => <h1 style={{ color: 'red' }} {...props} />,
  a: (props) => <a target="_blank" {...props} />
};

unified()
  .use(rehypeParse, { fragment: true })
  .use(rehypeReact, { createElement: React.createElement, components })
  .process('<h1>Заголовок</h1><a href="https://example.com">Ссылка</a>')
  .then(file => {
    ReactDOM.render(file.result, document.getElementById('root'));
  });

В этом примере:

  • components — объект провайдеров компонентов.
  • Ключи соответствуют тегам HTML (h1, a), а значения — функции-компоненты React.
  • Любой HTML-узел можно переопределить и изменить способ его отображения.

Провайдеры для Remark

Remark работает с Markdown. Провайдеры компонентов здесь используют AST-узлы типа MDAST:

  • heading
  • paragraph
  • link
  • list и др.

Особенность Remark: узлы Markdown не всегда соответствуют HTML-тегам напрямую. Поэтому провайдеры требуют сопоставления типов узлов с компонентами.

Пример интеграции с React:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeReact from 'rehype-react';
import React from 'react';
import ReactDOM from 'react-dom';

const components = {
  h2: (props) => <h2 style={{ fontStyle: 'italic' }} {...props} />,
  p: (props) => <p style={{ lineHeight: 1.6 }} {...props} />
};

unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeReact, { createElement: React.createElement, components })
  .process('# Заголовок уровня 1\n\nПараграф текста.')
  .then(file => {
    ReactDOM.render(file.result, document.getElementById('root'));
  });
  • remarkParse преобразует Markdown в MDAST.
  • remarkRehype конвертирует MDAST в HAST.
  • rehypeReact рендерит HAST через React-компоненты.

Контекст и каскадирование провайдеров

Провайдеры поддерживают каскадирование и переопределение компонентов:

  1. Глобальный провайдер — применяется ко всем узлам указанного типа.
  2. Локальный провайдер — может переопределять компонент на уровне узла.

Пример использования контекста:

const components = {
  p: (props) => <p style={{ color: props.color }}>Текст: {props.children}</p>
};

const MyContext = React.createContext({ color: 'blue' });

function App() {
  const contextValue = { color: 'green' };

  return (
    <MyContext.Provider value={contextValue}>
      <ReactMarkdown components={components}>
        {'Параграф текста'}
      </ReactMarkdown>
    </MyContext.Provider>
  );
}
  • Провайдер компонентов получает свойства через контекст.
  • Это позволяет динамически менять стиль и поведение компонентов без изменения AST.

Расширение функциональности через провайдеры

Провайдеры можно использовать для:

  • Поддержки интерактивных компонентов (Tooltip, Button).
  • Добавления кастомных атрибутов и классов.
  • Обработки сложных Markdown-структур, таких как таблицы, footnote или code block с подсветкой синтаксиса.

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

const components = {
  code({ className, children }) {
    const language = className?.replace('language-', '');
    return <SyntaxHighlighter language={language}>{children}</SyntaxHighlighter>;
  }
};
  • Провайдер получает className с типом языка.
  • Использует библиотеку react-syntax-highlighter для рендеринга.
  • Позволяет интегрировать сложную визуализацию без вмешательства в исходный Markdown.

Практические рекомендации

  • Использовать объекты компонентов вместо функций высшего порядка, когда требуется простое переопределение.
  • Применять контексты для передачи глобальных свойств стилей и настроек.
  • Разделять провайдеры для Remark и Rehype, чтобы сохранять ясность конвертации Markdown → HTML → React.
  • Для больших проектов строить иерархию провайдеров, чтобы не дублировать логику рендеринга для однотипных узлов.

Провайдеры компонентов являются мощным инструментом, который превращает статический Markdown или HTML в гибкую и динамическую систему визуализации. Они дают полный контроль над узлами AST и позволяют интегрировать сложные UI-компоненты без изменения исходного контента.