Remark — это экосистема парсеров и трансформеров для Markdown, работающих на JavaScript. Она строится вокруг представления документа в виде абстрактного синтаксического дерева (AST). Rehype выполняет аналогичную работу, но с HTML, позволяя трансформировать, анализировать и модифицировать HTML-структуры.
highlight.js — библиотека для подсветки синтаксиса кода. Она автоматически определяет язык блока кода и применяет стили, преобразуя текст кода в HTML с CSS-классами для последующего форматирования.
Интеграция Remark/Rehype с highlight.js позволяет преобразовывать Markdown с кодом в HTML, где каждый блок кода будет подсвечен, сохраняя структуру документа.
Для начала необходимо установить зависимости:
npm install remark remark-html rehype rehype-highlight highlight.js
remark — ядро для работы с Markdown.remark-html — плагин для преобразования Markdown в
HTML.rehype — ядро для работы с HTML AST.rehype-highlight — плагин для интеграции highlight.js в
Rehype.highlight.js — сама библиотека подсветки.Основной поток работы состоит из нескольких шагов:
Пример кода:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeHighlight from 'rehype-highlight';
import fs from 'fs';
const markdown = fs.readFileSync('example.md', 'utf-8');
const html = await unified()
.use(remarkParse) // Парсинг Markdown в AST
.use(remarkRehype) // Преобразование в HTML AST
.use(rehypeHighlight) // Подсветка кода
.use(rehypeStringify) // Преобразование AST в HTML
.process(markdown);
console.log(String(html));
Особенности работы rehype-highlight:
В проектах с большим количеством языков иногда требуется подключать только нужные языки для сокращения размера бандла:
import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';
import python from 'highlight.js/lib/languages/python';
hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('python', python);
Затем передаем этот кастомный объект в rehype-highlight:
.use(rehypeHighlight, { languages: hljs.listLanguages().reduce((acc, lang) => {
acc[lang] = hljs.getLanguage(lang);
return acc;
}, {}) })
Для корректного отображения подсвеченного кода необходимо подключить CSS темы. Пример:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.8.0/styles/github.css">
Highlight.js поддерживает большое количество встроенных тем:
github, atom-one-dark, monokai,
vs, dracula и другие.
Rehype позволяет изменять HTML AST перед генерацией финального HTML.
Например, можно добавлять свои классы или атрибуты к блокам
<pre>:
.use(() => (tree) => {
visit(tree, 'element', (node) => {
if (node.tagName === 'pre') {
node.properties.className = (node.properties.className || []).concat('custom-pre');
}
});
});
По умолчанию rehype-highlight работает с блочными элементами
<pre><code>. Для инлайнового кода можно
использовать rehype-sanitize и обрабатывать теги
<code> отдельно.
Если требуется обрабатывать несколько Markdown-файлов одновременно,
unified().process() возвращает Promise, что
удобно для интеграции с современными сборщиками и серверными
приложениями.
TypeError: node.type is undefined.fetch и других API, если темы
загружаются динамически через CDN.<pre><code> блокамЭтот подход обеспечивает гибкость: можно добавлять новые плагины, фильтровать или модифицировать AST, использовать кастомные стили и интегрировать процесс в любые веб-приложения на Node.js или в браузере.