Remark плагины

Remark — это экосистема плагинов для обработки Markdown и MDX, предоставляющая гибкий инструмент для трансформации и анализа контента. Основная идея заключается в том, что Markdown-документ преобразуется в абстрактное синтаксическое дерево (AST), которое затем можно изменять с помощью плагинов перед конвертацией в HTML или JSX.


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

Remark оперирует через цепочку плагинов, каждый из которых получает на вход дерево Markdown AST (MDAST). Плагин может:

  • читать структуру документа,
  • изменять узлы дерева,
  • добавлять новые элементы,
  • удалять или фильтровать существующие узлы.

Результат обработки передается следующему плагину в цепочке.

import {remark} from 'remark';
import remarkHtml from 'remark-html';

remark()
  .use(remarkHtml)
  .process('# Заголовок')
  .then(file => {
    console.log(String(file));
  });

В примере выше remark-html преобразует Markdown в HTML. Каждая стадия может быть расширена собственными плагинами.


Основные типы плагинов

  1. Parser plugins (Парсеры) Отвечают за чтение исходного Markdown или MDX и создание MDAST. Пример: remark-parse — стандартный парсер Markdown.

  2. Transformer plugins (Трансформеры) Манипулируют AST, изменяя узлы документа. Примеры:

    • remark-slug — добавляет id к заголовкам.
    • remark-autolink-headings — оборачивает заголовки в ссылку для быстрого доступа.
  3. Compiler plugins (Компиляторы) Преобразуют MDAST в другой формат: HTML, JSX или MDX. Примеры: remark-html, remark-mdx.


Создание собственного Remark плагина

Remark-плагин — это функция, принимающая AST и опции:

function remarkExample(options = {}) {
  return (tree) => {
    visit(tree, 'heading', node => {
      if (options.prefix) {
        node.children.unshift({type: 'text', value: options.prefix});
      }
    });
  };
}

Здесь используется утилита visit из пакета unist-util-visit, позволяющая обходить дерево. Плагин модифицирует все заголовки, добавляя префикс.


Работа с MDX

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

import {remark} from 'remark';
import remarkMdx from 'remark-mdx';
import remarkSlug from 'remark-slug';

remark()
  .use(remarkMdx)
  .use(remarkSlug)
  .processSync('# Заголовок MDX');
  • remark-mdx превращает MDX в MDAST с поддержкой JSX-узлов.
  • remark-slug работает только с Markdown-заголовками, JSX не трогая.

Совмещение с Rehype

Remark часто интегрируют с Rehype, чтобы конвертировать Markdown/MDX в HTML через промежуточный HAST (HTML AST):

import {remark} from 'remark';
import remarkHtml from 'remark-html';
import rehypeRaw from 'rehype-raw';
import rehypeSanitize from 'rehype-sanitize';

remark()
  .use(remarkHtml)
  .use(rehypeRaw)
  .use(rehypeSanitize)
  .process('# Пример с <b>HTML</b>');

Преимущество такого подхода — возможность безопасной вставки HTML и расширенных трансформаций.


Популярные Remark плагины

  • remark-lint — проверка Markdown на соответствие стилевым правилам.
  • remark-frontmatter — поддержка YAML/JSON фронтматтеров.
  • remark-gfm — расширения GitHub Flavored Markdown (таблицы, задачи, зачеркнутый текст).
  • remark-toc — автоматическая генерация оглавления.

Каждый плагин можно настраивать через объект options, передаваемый в use.


Практические советы

  • Плагины следует подключать в правильном порядке: сначала парсеры, затем трансформеры, потом компиляторы.
  • Для обработки MDX рекомендуется сначала обрабатывать Markdown-плагины, затем JSX.
  • Собственные плагины лучше делать чистыми функциями, чтобы не изменять глобальные объекты и легко интегрировать в цепочку remark().use(...).
  • Для обхода дерева стоит использовать unist-util-visit, что делает код универсальным и читаемым.

Интеграция с проектами

  • В Next.js MDX используется через @next/mdx или next-mdx-remote, где Remark-плагины подключаются в конфигурации.
  • В Gatsby MDX-плагины передаются в gatsby-plugin-mdx.
  • Для CLI-обработки Markdown можно использовать remark-cli с .remarkrc или программно через API remark().use(...).

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