Frontmatter — это специальный блок метаданных,
помещаемый в начало Markdown-документа. Обычно он оформляется с
использованием YAML (но возможны JSON и TOML) и заключён между тройными
дефисами ---. Frontmatter используется для хранения
информации о документе: заголовок, автор, дата, категории, теги, ключи
конфигурации и любые пользовательские данные.
Пример YAML-frontmatter:
---
title: "Основы Remark и Rehype"
author: "Иван Иванов"
date: 2026-03-22
tags:
- javascript
- markdown
- rehype
draft: false
---
После блока frontmatter идёт сам Markdown-контент, который будет преобразован библиотеками Remark и Rehype.
Для работы с frontmatter в Remark используется плагин remark-frontmatter. Он позволяет распознавать YAML, TOML и другие блоки и преобразовывать их в узлы синтаксического дерева (AST).
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkFrontmatter from 'remark-frontmatter';
import yaml from 'js-yaml';
const markdown = `
---
title: "Пример статьи"
date: "2026-03-22"
---
# Заголовок
Контент статьи.
`;
const processor = unified()
.use(remarkParse)
.use(remarkFrontmatter, ['yaml']);
const tree = processor.parse(markdown);
// Пример извлечения YAML
tree.children
.filter(node => node.type === 'yaml')
.forEach(node => {
const data = yaml.load(node.value);
console.log(data.title); // "Пример статьи"
});
Ключевые моменты:
remarkFrontmatter добавляет узлы типа yaml
или toml в AST.js-yaml) или TOML.Remark обрабатывает Markdown в AST MDAST, а Rehype работает с HTML-деревом HAST. Для передачи контента с метаданными используют remark-rehype.
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const html = await unified()
.use(remarkParse)
.use(remarkFrontmatter, ['yaml'])
.use(remarkRehype)
.use(rehypeStringify)
.process(markdown);
console.log(String(html));
Особенности:
metadata, который
передаётся в шаблоны или дальнейшие плагины Rehype.Remark позволяет создавать собственные плагины для обработки frontmatter и добавления его в контекст обработки документа.
function remarkExtractFrontmatter() {
return (tree, file) => {
const yamlNode = tree.children.find(node => node.type === 'yaml');
if (yamlNode) {
const data = yaml.load(yamlNode.value);
file.data.frontmatter = data;
}
};
}
const processor = unified()
.use(remarkParse)
.use(remarkFrontmatter, ['yaml'])
.use(remarkExtractFrontmatter)
.use(remarkRehype)
.use(rehypeStringify);
const file = await processor.process(markdown);
console.log(file.data.frontmatter.title); // "Пример статьи"
Примечания:
file.data — объект, используемый для хранения
пользовательских данных, доступных на всех этапах обработки.zod или joi для валидации frontmatter перед
дальнейшей обработкой.remark-toc,
remark-slug и другими, чтобы динамически создавать
оглавление или идентификаторы.metadata.import fs from 'fs';
import path from 'path';
const filePath = path.join(process.cwd(), 'article.md');
const markdownContent = fs.readFileSync(filePath, 'utf-8');
const file = await unified()
.use(remarkParse)
.use(remarkFrontmatter, ['yaml'])
.use(remarkExtractFrontmatter)
.use(remarkRehype)
.use(rehypeStringify)
.process(markdownContent);
const htmlContent = String(file);
const metadata = file.data.frontmatter;
console.log({ htmlContent, metadata });
Такой подход позволяет отделить структуру документа и метаданные, что упрощает генерацию статических сайтов, блогов и документации с динамическими заголовками, тегами и настройками рендеринга.