Логирование в экосистеме Remark и Rehype играет ключевую роль при разработке и отладке плагинов. Благодаря корректной организации логов можно отслеживать процесс обработки AST (Abstract Syntax Tree), выявлять ошибки трансформации и понимать, как плагин взаимодействует с данными. Remark и Rehype используют унифицированную структуру AST, что позволяет создавать единые подходы к логированию как для Markdown, так и для HTML.
В плагинах Remark и Rehype чаще всего используют встроенный механизм
через объект vfile. VFile представляет собой виртуальный
файл и содержит полезные свойства для работы с логами:
message, info, fatal. Каждое
сообщение в vfile имеет уровень важности и метку позиции,
что позволяет точно локализовать проблему в исходном файле.
Пример базового использования:
import { visit } from 'unist-util-visit';
function remarkPluginExample() {
return (tree, file) => {
visit(tree, 'text', (node) => {
if (node.value.includes('TODO')) {
file.message('Найден TODO в тексте', node);
}
});
};
}
file.message(text, node) — создает обычное
информационное сообщение.file.warn(text, node) — лог уровня предупреждения.file.fail(text, node) — лог уровня ошибки, прерывающий
процесс обработки.Все эти методы автоматически привязывают сообщение к конкретной позиции в исходном AST, что значительно облегчает поиск и исправление ошибок.
Сообщения VFile могут включать следующие поля:
reason — описание проблемы.line, column — позиция в исходном
файле.source — имя плагина или модуля, который сгенерировал
сообщение.fatal — булево значение, указывающее, что это
критическая ошибка.Например:
file.message('Некорректное использование ссылки', node, { source: 'remark-my-plugin' });
Это создаст сообщение с меткой источника, которое может быть удобно обработано в консоли или в лог-системе CI/CD.
Для асинхронных плагинов важно учитывать, что сообщения VFile могут создаваться после завершения основной обработки дерева. Поэтому нужно использовать асинхронные функции с корректной передачей VFile:
export default async function remarkAsyncPlugin() {
return async (tree, file) => {
await visit(tree, 'link', async (node) => {
const isValid = await validateUrl(node.url);
if (!isValid) {
file.message(`Недопустимый URL: ${node.url}`, node);
}
});
};
}
Асинхронное логирование не блокирует процесс обработки и позволяет интегрировать внешние проверки, например, запросы к API или проверку существования ресурсов.
Для расширенной отладки можно внедрять собственные уровни
логирования. Например, можно использовать объект file.data
для хранения структурированных логов:
function logPlugin(tree, file) {
if (!file.data.logs) file.data.logs = [];
visit(tree, 'heading', (node) => {
file.data.logs.push({ type: 'heading', value: node.value });
});
}
Такой подход позволяет:
Для более сложных плагинов часто используется внешнее логирование с
console, debug или библиотеками вроде
pino или winston. Однако в контексте
Remark/Rehype рекомендуется синхронизировать их с VFile, чтобы сообщения
оставались привязанными к позициям исходного текста.
Пример интеграции:
import debug from 'debug';
const log = debug('remark:plugin');
function debugPlugin(tree, file) {
visit(tree, 'paragraph', (node) => {
log('Обработан абзац: %O', node);
file.message('Обработан абзац', node);
});
}
Это позволяет одновременно вести подробный отладочный лог и сохранять сообщения в структуре VFile.
message, warn и fail для
различной критичности.file.data для последующего анализа.unist-util-visit.file.message, file.warn или
file.fail.file.data или выводиться во
внешние системы.Такой подход обеспечивает прозрачность работы плагинов, облегчает отладку и позволяет создавать расширяемые и надежные решения для обработки Markdown и HTML с помощью Remark и Rehype.