Для начала работы с Remark и Rehype требуется создать минимальный проект на Node.js. Основными зависимостями будут:
npm init -y
npm install remark remark-parse remark-stringify rehype rehype-parse rehype-stringify unified
unified — ядро системы для обработки AST (Abstract
Syntax Tree).remark-parse и remark-stringify — парсер и
сериализатор Markdown.rehype-parse и rehype-stringify — парсер и
сериализатор HTML.Создание базовой структуры проекта:
project/
├─ src/
│ └─ index.js
├─ package.json
└─ README.md
Remark работает через систему плагинов, которые подключаются к процессору. Простейший пример:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
const processor = unified()
.use(remarkParse) // преобразует Markdown в AST
.use(remarkStringify); // преобразует AST обратно в Markdown
const markdown = '# Заголовок\n\nТекст параграфа.';
processor.process(markdown).then(file => {
console.log(String(file));
});
Ключевые моменты:
unified().use(plugin) создаёт цепочку обработки.process возвращает объект VFile,
содержащий результат преобразования.Rehype предназначен для работы с HTML. Базовая настройка аналогична:
import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(rehypeParse, { fragment: true }) // парсинг HTML-фрагмента
.use(rehypeStringify); // обратное преобразование в HTML
const html = '<h1>Заголовок</h1><p>Текст параграфа.</p>';
processor.process(html).then(file => {
console.log(String(file));
});
Особенности:
{ fragment: true } позволяет обрабатывать
отдельные фрагменты HTML, а не полный документ.Для конвертации Markdown в HTML используется связка:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkRehype) // преобразует AST Markdown в AST HTML
.use(rehypeStringify);
const markdown = '# Заголовок\n\nТекст параграфа.';
processor.process(markdown).then(file => {
console.log(String(file));
});
Важные моменты:
remark-rehype — мост между Markdown и HTML AST.VFile позволяет хранить метаданные и путь исходного файла:
import { VFile } from 'vfile';
const file = new VFile({
path: 'example.md',
contents: '# Заголовок\nТекст параграфа'
});
processor.process(file).then(result => {
console.log(result.contents);
});
Преимущества использования VFile:
Добавление плагина для преобразования текста в верхний регистр:
function uppercase() {
return (tree) => {
visit(tree, 'text', (node) => {
node.value = node.value.toUpperCase();
});
};
}
import { visit } from 'unist-util-visit';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
const processor = unified()
.use(remarkParse)
.use(uppercase)
.use(remarkStringify);
processor.process('# Заголовок\nТекст параграфа.').then(file => {
console.log(String(file));
});
Пояснения:
visit(tree, type, callback) обход дерева AST.Часто требуется обработка Markdown файлов из проекта:
import fs from 'fs/promises';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
async function convertFile(filePath) {
const content = await fs.readFile(filePath, 'utf-8');
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify);
const file = await processor.process(content);
await fs.writeFile(filePath.replace(/\.md$/, '.html'), String(file));
}
convertFile('src/example.md');
Принципы работы:
fs.readFile.Минимальная конфигурация проекта с Remark/Rehype строится на трёх
китах: unified, плагины для парсинга/сериализации и VFile
для управления файлами и метаданными. Такая структура позволяет
постепенно расширять функционал, добавляя кастомные плагины и интеграцию
с другими инструментами, не усложняя базовую настройку.