rehype-highlight: подсветка синтаксиса

rehype-highlight — это плагин для экосистемы Rehype, позволяющий добавлять подсветку синтаксиса к элементам <code> в HTML-документах. Он работает на основе библиотеки highlight.js, автоматически распознавая язык программирования или используя явное указание языка через класс.


Установка и подключение

Для работы с rehype-highlight необходимы следующие зависимости:

npm install rehype rehype-highlight highlight.js

Подключение плагина в коде выглядит так:

import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeHighlight from 'rehype-highlight';
import rehypeStringify from 'rehype-stringify';
import fs from 'fs';

const html = fs.readFileSync('example.html', 'utf-8');

const processedHtml = await unified()
  .use(rehypeParse, { fragment: true })
  .use(rehypeHighlight)
  .use(rehypeStringify)
  .process(html);

console.log(String(processedHtml));

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

  • rehypeParse преобразует HTML в дерево HAST.
  • rehypeHighlight добавляет классы для подсветки синтаксиса.
  • rehypeStringify превращает HAST обратно в HTML.

Настройка языков

По умолчанию rehype-highlight использует все языки, предоставляемые highlight.js. Для уменьшения размера сборки можно подключать только необходимые языки:

import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';
import python from 'highlight.js/lib/languages/python';
import rehypeHighlight from 'rehype-highlight';

hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('python', python);

const processedHtml = await unified()
  .use(rehypeParse, { fragment: true })
  .use(rehypeHighlight, { subset: ['javascript', 'python'] })
  .use(rehypeStringify)
  .process(html);

Пояснение:

  • hljs.registerLanguage позволяет регистрировать конкретные языки.
  • Опция subset в rehype-highlight сокращает загрузку ненужных языковых файлов.

Определение языка в коде

Для корректной подсветки важно указывать язык в атрибуте class элемента <code>:

<pre><code class="language-javascript">
function add(a, b) {
  return a + b;
}
</code></pre>

Если язык не указан, rehype-highlight попытается автоматически определить его. Автоопределение полезно, но может работать некорректно для коротких фрагментов кода.


Пользовательские стили

Подсветка синтаксиса требует CSS. highlight.js предоставляет готовые темы:

npm install highlight.js

Подключение CSS в проекте:

import 'highlight.js/styles/github.css';

Можно использовать любую другую тему, например monokai, atom-one-dark, github-dark, чтобы подстроить визуальный стиль под проект.


Применение вместе с Remark

Для обработки Markdown можно объединять remark и rehype:

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)
  .use(remarkRehype)
  .use(rehypeHighlight)
  .use(rehypeStringify)
  .process(markdown);

console.log(String(html));

Особенности:

  • remarkParse конвертирует Markdown в AST.
  • remarkRehype преобразует Markdown AST в HAST.
  • rehypeHighlight добавляет подсветку к блокам кода.
  • rehypeStringify возвращает финальный HTML.

Обработка нескольких блоков кода

Если в документе несколько языков, rehype-highlight корректно обрабатывает каждый блок независимо. Важно:

  • Указывать класс language-<имя> для каждого блока.
  • Подключить соответствующий язык через highlight.js или разрешить автоопределение.
<pre><code class="language-python">
def greet(name):
    print(f"Hello, {name}")
</code></pre>

<pre><code class="language-javascript">
const greet = name => console.log(`Hello, ${name}`);
</code></pre>

Каждый блок будет подсвечен в соответствии с языком.


Расширенные настройки

rehype-highlight поддерживает дополнительные параметры:

  • ignoreMissing: true — не выбрасывать ошибку, если язык не найден.
  • subset — массив языков, для которых делать подсветку.
  • prefix — префикс для CSS-классов, чтобы избежать конфликтов с существующими стилями.

Пример:

.use(rehypeHighlight, {
  ignoreMissing: true,
  prefix: 'hljs-',
  subset: ['javascript', 'python']
})

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

  • Для крупных проектов лучше использовать subset языков, чтобы не загружать весь highlight.js.
  • Всегда подключать CSS тему, иначе подсветка будет не видна.
  • Для динамического контента (например, Markdown из CMS) рекомендуется включать автоопределение языка.
  • Для кастомных стилей можно переопределять классы .hljs, .hljs-keyword, .hljs-string и т.д.

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