Remark и Rehype — это мощные инструменты для работы с Markdown и HTML в экосистеме JavaScript. Remark отвечает за обработку Markdown, а Rehype — за HTML, что позволяет гибко интегрировать скрипты и стили в генерируемый контент.
Для начала необходимо установить пакеты:
npm install remark remark-html rehype rehype-stringify
Remark выполняет разбор Markdown в AST (Abstract Syntax Tree), а Rehype превращает этот AST в HTML. Встраивание скриптов и стилей чаще всего происходит на этапе Rehype.
import {remark} from 'remark';
import remarkHtml from 'remark-html';
import {rehype} from 'rehype';
import rehypeStringify from 'rehype-stringify';
const markdown = `
# Заголовок
Пример текста с кастомным стилем и скриптом
`;
const html = await remark()
.use(remarkHtml)
.process(markdown);
console.log(String(html));
Для добавления стилей прямо в HTML-элементы используется
Rehype-плагин rehype-raw для обработки уже сгенерированного
HTML и модификации дерева DOM.
import rehypeRaw from 'rehype-raw';
import rehypeAddClasses from 'rehype-add-classes';
const htmlWithStyles = await rehype()
.data('settings', {fragment: true})
.use(rehypeRaw)
.use(rehypeAddClasses, {h1: 'main-title', p: 'text-body'})
.use(rehypeStringify)
.process(String(html));
console.log(String(htmlWithStyles));
Здесь rehypeAddClasses позволяет добавить CSS-классы к
определённым тегам. Это удобно для систематизации стилей и интеграции с
CSS-фреймворками.
Для подключения внешних ресурсов можно динамически создавать элементы
link и script в дереве HTML:
import {visit} from 'unist-util-visit';
function addScriptsAndStyles() {
return (tree) => {
visit(tree, 'root', (node) => {
node.children.unshift({
type: 'element',
tagName: 'link',
properties: {rel: 'stylesheet', href: '/styles.css'},
children: [],
});
node.children.push({
type: 'element',
tagName: 'script',
properties: {src: '/script.js', defer: true},
children: [],
});
});
};
}
const enhancedHtml = await rehype()
.data('settings', {fragment: true})
.use(rehypeRaw)
.use(addScriptsAndStyles)
.use(rehypeStringify)
.process(String(html));
console.log(String(enhancedHtml));
visit из unist-util-visit
позволяет обходить дерево и модифицировать его узлы.link и script можно вставлять в начало или
конец документа для корректной загрузки ресурсов.Inline-скрипты можно вставлять через AST:
function addInlineScript(scriptContent) {
return (tree) => {
visit(tree, 'root', (node) => {
node.children.push({
type: 'element',
tagName: 'script',
properties: {},
children: [{type: 'text', value: scriptContent}],
});
});
};
}
const scriptContent = `
console.log('Hello from inline script');
`;
const htmlWithInlineScript = await rehype()
.data('settings', {fragment: true})
.use(rehypeRaw)
.use(addInlineScript, scriptContent)
.use(rehypeStringify)
.process(String(html));
Важно: inline-скрипты увеличивают риск XSS-атак, поэтому рекомендуется фильтровать контент или использовать CSP (Content Security Policy).
Rehype позволяет не только добавлять новые скрипты и стили, но и модифицировать существующие элементы:
function modifyExistingStyles() {
return (tree) => {
visit(tree, 'element', (node) => {
if (node.tagName === 'p') {
node.properties.style = 'color: red; font-weight: bold;';
}
});
};
}
const htmlModified = await rehype()
.data('settings', {fragment: true})
.use(rehypeRaw)
.use(modifyExistingStyles)
.use(rehypeStringify)
.process(String(html));
Remark и Rehype отлично работают в связке с Webpack, Vite или Astro:
import remarkGfm from 'remark-gfm';
import rehypePrism from '@mapbox/rehype-prism';
const processedHtml = await remark()
.use(remarkGfm)
.use(remarkHtml)
.use(() => rehype().use(rehypePrism))
.process(markdown);
remarkGfm добавляет поддержку GitHub
Flavored Markdown.rehypePrism позволяет подсвечивать
код, при этом можно внедрять собственные скрипты для
интерактивности.fragment: true для генерации частей HTML,
а не полного документа, если планируется дальнейшая интеграция.Remark и Rehype предоставляют гибкий и мощный инструментальный набор для внедрения скриптов и стилей. Работа с AST позволяет точно контролировать содержимое, обеспечивая высокую степень кастомизации HTML и безопасное управление ресурсами.