Интеграция с MathJax

Remark и Rehype — это мощные инструменты для парсинга и трансформации Markdown и HTML в экосистеме JavaScript. В случае работы с математическими выражениями требуется подключение MathJax для корректного отображения формул как в инлайновом, так и в блочном формате. Рассмотрим детально шаги интеграции, особенности конфигурации и оптимизацию производительности.


Поддержка математических выражений в Remark

Remark представляет Markdown как абстрактное синтаксическое дерево (AST). Для работы с математикой удобно использовать плагины, такие как remark-math:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkMath from 'remark-math';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

const processor = unified()
  .use(remarkParse)
  .use(remarkMath)
  .use(remarkRehype)
  .use(rehypeStringify);

const markdown = `
Инлайновая формула: $E = mc^2$

Блочная формула:
$$
\\int_0^\\infty e^{-x} dx = 1
$$
`;

const html = processor.processSync(markdown).toString();
console.log(html);

Ключевые моменты:

  • remark-math преобразует математические формулы в узлы inlineMath и math в AST, которые затем могут быть обработаны Rehype.
  • Блочные формулы заключаются в $$...$$, инлайновые — в $...$.
  • После преобразования Remark → Rehype HTML сохраняет теги <span class="math"> для инлайновых и <div class="math"> для блочных формул, что упрощает их обработку MathJax.

Обработка MathJax через Rehype

Rehype предоставляет возможность модифицировать HTML через плагины. Для интеграции MathJax используется рендеринг на стороне клиента или генерация HTML с необходимыми тегами и атрибутами.

Пример настройки:

import rehypeMathjax from 'rehype-mathjax';

const processor = unified()
  .use(remarkParse)
  .use(remarkMath)
  .use(remarkRehype)
  .use(rehypeMathjax)
  .use(rehypeStringify);

const html = processor.processSync(markdown).toString();
console.log(html);

Особенности rehype-mathjax:

  • Поддерживает различные режимы рендеринга: SVG (по умолчанию), CommonHTML.
  • Автоматически добавляет необходимые классы и атрибуты для MathJax.
  • Позволяет конфигурировать поведение через объект опций:
.use(rehypeMathjax, {
  output: 'svg',
  scale: 1.2,
  macros: {
    RR: '\\mathbb{R}'
  }
});
  • output — формат вывода (svg, chtml или mml).
  • scale — масштаб формул.
  • macros — пользовательские макросы, которые можно использовать в формуле.

Обработка больших документов и оптимизация

Для больших Markdown-документов или документации с множеством формул важно учитывать производительность:

  1. Ленивая загрузка MathJax: Подключение MathJax только при необходимости уменьшает время первоначальной загрузки страницы.

  2. Пакетная обработка формул: Если генерация HTML происходит на сервере, рекомендуется использовать пакетную генерацию MathJax через rehype-mathjax в режиме SVG, что снижает нагрузку на клиент.

  3. Минимизация CSS и скриптов: Для формул можно подключать только необходимые стили и шрифты MathJax, чтобы не увеличивать размер страницы.

  4. Кэширование результатов рендеринга: Если Markdown не меняется часто, удобно сохранять сгенерированный HTML с рендеренными формулами, чтобы повторно не запускать MathJax на клиенте.


Интеграция с React

При использовании React полезно оборачивать HTML с формулами в компонент с dangerouslySetInnerHTML, а MathJax запускать через хук useEffect:

import { useEffect } from 'react';
import { typeset } from 'mathjax-full/js/mathjax';

function MathContent({ html }) {
  useEffect(() => {
    typeset();
  }, [html]);

  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
  • typeset() инициирует рендеринг всех формул на странице.
  • Важно, чтобы HTML уже содержал правильные классы и элементы, которые создает rehype-mathjax.

Работа с кастомными макросами

MathJax поддерживает пользовательские команды для удобства написания сложных выражений:

.use(rehypeMathjax, {
  macros: {
    RR: '\\mathbb{R}',
    bold: ['\\mathbf{#1}', 1]
  }
});
  • В macros можно определять функции с аргументами, что упрощает повторяющееся форматирование формул.
  • Это особенно полезно в образовательных проектах, где часто используются одни и те же обозначения.

Обработка инлайновой и блочной математики

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

Remark + Rehype позволяют различать эти типы формул на уровне AST и HTML, что обеспечивает точное визуальное представление.


Поддержка MathJax 3.x и настройка конфигурации

MathJax 3.x использует модульную архитектуру:

<script type="module">
  import { mathjax } from 'mathjax/es5/tex-svg.js';

  mathjax.startup.defaultReady();
</script>
  • Плагин rehype-mathjax автоматически генерирует HTML, совместимый с этим подходом.
  • Можно задавать глобальные настройки, такие как displayAlign, font, scale, через объект MathJax перед рендерингом.

Итоговая структура интеграции

  1. Markdown → Remark (remark-parse + remark-math).
  2. Remark AST → Rehype AST (remark-rehype).
  3. Rehype AST → HTML с рендерингом MathJax (rehype-mathjax).
  4. Опциональная интеграция с React или другим фронтендом для динамического отображения формул.

Эта цепочка обеспечивает точную конвертацию математических выражений из Markdown в HTML с полноценной визуализацией, удобной для образовательных ресурсов, документации и научных публикаций.