Библиотеки Remark и Rehype предоставляют мощный механизм для работы с Markdown и HTML на уровне AST (Abstract Syntax Tree), что позволяет гибко настраивать обработку контента. Подсветка синтаксиса в кодовых блоках является одной из ключевых задач при визуализации документации, блогов и статей. Кастомные темы подсветки дают возможность создавать уникальный стиль отображения кода, согласованный с дизайном сайта или приложения.
Для подсветки кода часто используется связка Remark → Rehype →
rehype-prism или rehype-highlight. Принцип работы основан на
трансформации AST Markdown в AST HTML с последующей обработкой узлов
<code> и <pre>.
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 result = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeHighlight, { subset: ['javascript', 'css'] })
.use(rehypeStringify)
.process(markdown);
console.log(result.toString());
В этом примере rehype-highlight автоматически применяет
встроенные темы подсветки. Для кастомных стилей требуется подключить CSS
с определёнными классами для токенов.
Токены синтаксиса обычно получают классы вида
.token.keyword, .token.string,
.token.comment. Основная задача кастомной темы — задать
визуальные свойства этих классов:
pre code {
display: block;
padding: 1em;
background-color: #1e1e2f;
color: #dcdcdc;
border-radius: 6px;
overflow-x: auto;
}
.token.keyword { color: #ff5370; font-weight: bold; }
.token.string { color: #c3e88d; }
.token.comment { color: #6272a4; font-style: italic; }
.token.function { color: #82aaff; }
.token.variable { color: #f78c6c; }
CSS можно расширять, добавляя эффекты для идентификаторов, операторов и литералов, что позволяет создавать полное соответствие фирменному стилю.
rehype-prism-plus предоставляет более детализированные
возможности, включая поддержку плагинов для подсветки: линии, номера
строк и расширенные темы.
import rehypePrism from 'rehype-prism-plus';
import 'prismjs/themes/prism-okaidia.css'; // Базовая тема
const result = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypePrism, { plugins: ['line-numbers'] })
.use(rehypeStringify)
.process(markdown);
Чтобы кастомизировать тему, можно заменить стандартный CSS-файл на собственный, сохранив имена классов токенов или расширив их через CSS-переменные.
Для более сложных проектов создают динамические темы с помощью CSS-in-JS или препроцессоров:
import { css } from '@emotion/css';
const codeTheme = css`
pre code {
background-color: ${darkMode ? '#282a36' : '#f5f5f5'};
color: ${darkMode ? '#f8f8f2' : '#333'};
}
.token.keyword { color: ${darkMode ? '#ff79c6' : '#d73a49'}; }
.token.string { color: ${darkMode ? '#f1fa8c' : '#032f62'}; }
`;
Использование таких подходов позволяет менять тему подсветки на лету, например, при переключении пользовательского интерфейса между светлым и тёмным режимом.
Remark и Rehype позволяют обрабатывать узлы AST до передачи их на подсветку. Можно создать плагин, который добавляет новые типы токенов или модифицирует существующие:
function rehypeCustomTokens() {
return (tree) => {
visit(tree, 'element', (node) => {
if (node.tagName === 'code' && node.properties.className?.includes('language-js')) {
node.children.forEach((child) => {
if (child.type === 'text' && child.value.includes('TODO')) {
child.type = 'element';
child.tagName = 'span';
child.properties = { className: ['token', 'todo'] };
}
});
}
});
};
}
После этого можно задать стиль для .token.todo, выделяя
определённые комментарии или ключевые слова по своему вкусу.
rehype-highlight и кастомный CSS, если
необходимо быстро внедрить визуальные изменения.Кастомные темы в Remark и Rehype позволяют создавать гибкую и выразительную подсветку, полностью контролируемую через CSS и плагины AST, что делает библиотеку мощным инструментом для любой веб-документации и платформ, работающих с Markdown и HTML.