Использование в браузере

Для работы с библиотеками Remark и Rehype в браузере используется сборка через модули ES или подключение через CDN. Вариант с ES-модулями требует настройки сборщика вроде Vite или Webpack. Пример подключения через CDN:

<script type="module">
  import { unified } from 'https://cdn.jsdelivr.net/npm/unified@11/+esm';
  import { remarkParse } from 'https://cdn.jsdelivr.net/npm/remark-parse@10/+esm';
  import { remarkRehype } from 'https://cdn.jsdelivr.net/npm/remark-rehype@10/+esm';
  import { rehypeStringify } from 'https://cdn.jsdelivr.net/npm/rehype-stringify@10/+esm';

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

  const markdown = '# Заголовок 1\n\nТекст с **жирным** выделением.';
  const html = await processor.process(markdown);
  console.log(String(html));
</script>

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


Основные шаги преобразования Markdown в HTML

1. Разбор Markdown remarkParse превращает строку Markdown в AST (Abstract Syntax Tree) формата MDAST, представляющий структуру документа. В этом дереве каждая нода описывает тип контента: параграф, заголовок, список, ссылку, изображение.

2. Преобразование MDAST в HAST remarkRehype переводит MDAST в HAST (HTML AST). Этот шаг позволяет использовать возможности Rehype, включая модификацию тегов, атрибутов и интеграцию с другими плагинами, например для добавления классов к элементам или вставки пользовательских компонентов.

3. Генерация HTML rehypeStringify превращает HAST обратно в HTML-строку. В браузере результат можно вставлять в DOM с помощью innerHTML или создавать виртуальные элементы для дальнейшей обработки.


Работа с плагинами Remark и Rehype

Плагины расширяют функциональность библиотек:

  • Remark-плагины работают с MDAST. Например, remark-gfm добавляет поддержку GitHub Flavored Markdown, включая таблицы и чекбоксы.
  • Rehype-плагины работают с HAST. Например, rehype-highlight позволяет подсвечивать синтаксис кода, а rehype-slug автоматически добавляет идентификаторы заголовкам.

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

import { remarkGfm } from 'https://cdn.jsdelivr.net/npm/remark-gfm@3/+esm';
import { rehypeHighlight } from 'https://cdn.jsdelivr.net/npm/rehype-highlight@6/+esm';

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

const markdown = `
# Код с подсветкой

\`\`\`javascript
console.log('Hello World');
\`\`\`
`;
const html = await processor.process(markdown);
document.body.innerHTML = String(html);

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


Асинхронные плагины и обработка данных

Некоторые плагины, особенно те, что загружают данные из внешних источников или делают асинхронную обработку, требуют await processor.process(). Важно использовать await внутри асинхронной функции или then() при цепочках промисов.

(async () => {
  const html = await processor.process(markdown);
  document.body.innerHTML = String(html);
})();

Модификация AST в браузере

Remark и Rehype предоставляют API для программной модификации AST:

import { visit } from 'https://cdn.jsdelivr.net/npm/unist-util-visit@4/+esm';

const processor = unified()
  .use(remarkParse)
  .use(() => (tree) => {
    visit(tree, 'heading', (node) => {
      node.children.push({ type: 'text', value: ' ?' });
    });
  })
  .use(remarkRehype)
  .use(rehypeStringify);

const html = await processor.process('# Заголовок');
document.body.innerHTML = String(html);

В этом примере к каждому заголовку добавляется эмодзи. Использование visit позволяет рекурсивно обходить дерево и изменять любые ноды.


Интеграция с DOM и динамическая генерация контента

После преобразования Markdown в HTML результат можно вставлять в страницу динамически:

const container = document.getElementById('content');
container.innerHTML = String(await processor.process(markdown));

При этом можно комбинировать с динамическими данными, подставляя их в Markdown перед обработкой.


Оптимизация работы в браузере

  • Lazy Loading плагинов: подключение тяжелых плагинов только при необходимости.
  • Кеширование AST: если один и тот же Markdown обрабатывается несколько раз.
  • Web Workers: для тяжёлых преобразований использовать отдельный поток, чтобы не блокировать UI.

Пример использования Web Worker для Remark:

// worker.js
importScripts('https://cdn.jsdelivr.net/npm/unified@11/+esm', 
             'https://cdn.jsdelivr.net/npm/remark-parse@10/+esm',
             'https://cdn.jsdelivr.net/npm/remark-rehype@10/+esm',
             'https://cdn.jsdelivr.net/npm/rehype-stringify@10/+esm');

self.onmess age = async (e) => {
  const processor = unified()
    .use(remarkParse)
    .use(remarkRehype)
    .use(rehypeStringify);

  const html = await processor.process(e.data);
  self.postMessage(String(html));
};

Главная страница передает Markdown в воркер и получает готовый HTML без задержек интерфейса.


Этот подход позволяет использовать Remark и Rehype полностью в браузере, обрабатывая Markdown, подключая плагины, модифицируя AST и динамически вставляя HTML в DOM.