Серверный рендеринг

Для начала работы с библиотекой Marked в серверной среде Node.js необходимо установить её через npm:

npm install marked

После установки библиотеку подключают стандартным способом:

const { marked } = require('marked');

В случае использования ES-модулей:

import { marked } from 'marked';

Преобразование Markdown в HTML

Основной функционал библиотеки заключается в конвертации текста из Markdown в HTML. Для этого используется функция marked():

const markdownText = `
# Заголовок уровня 1

Это **жирный** текст и *курсив*.
`;

const html = marked(markdownText);
console.log(html);

В результате получится HTML с корректной структурой тегов <h1>, <strong> и <em>.

Настройка парсера

Marked предоставляет гибкую систему конфигурации через объект опций, который передаётся в marked.setOptions():

marked.setOptions({
  gfm: true,               // включение GitHub Flavored Markdown
  breaks: false,           // перенос строк по Enter
  smartLists: true,        // умные списки
  smartypants: true,       // преобразование кавычек и дефисов в типографские символы
  headerIds: true,         // генерация id для заголовков
});

Эти опции позволяют адаптировать рендеринг под конкретные требования проекта.

Использование собственного рендерера

Marked позволяет создавать пользовательский рендерер, чтобы полностью контролировать генерацию HTML. Например:

const renderer = new marked.Renderer();

renderer.heading = function (text, level) {
  return `<h${level} class="custom-header">${text}</h${level}>`;
};

const htmlCustom = marked('# Тестовый заголовок', { renderer });
console.log(htmlCustom);

В этом примере заголовки будут рендериться с классом custom-header, что удобно для стилизации на сервере перед отправкой клиенту.

Асинхронный рендеринг и безопасный HTML

Для проектов с небезопасным Markdown (например, полученным от пользователей) важно использовать асинхронный рендеринг с возможностью фильтрации HTML через sanitize или интеграцию с библиотеками вроде DOMPurify:

import DOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';

const window = (new JSDOM('')).window;
const DOMPurifyInstance = DOMPurify(window);

const unsafeMarkdown = 'Пример с <script>alert("XSS")</script>';

const safeHtml = DOMPurifyInstance.sanitize(marked(unsafeMarkdown));

Такой подход предотвращает выполнение вредоносного кода при серверной генерации HTML.

Потоковая обработка больших документов

Для работы с большим объемом Markdown эффективнее использовать токены и потоки:

const lexer = new marked.Lexer();
const tokens = lexer.lex(largeMarkdownText);

tokens.forEach(token => {
  // обработка каждого токена
});

const html = marked.parser(tokens);

Разделение на лексический и синтаксический этап позволяет оптимизировать производительность и контролировать процесс рендеринга на сервере.

Интеграция с серверными фреймворками

Marked легко интегрируется с Express.js, Koa и другими серверными платформами. Пример middleware для Express:

app.post('/render', (req, res) => {
  const markdown = req.body.markdown || '';
  const html = marked(markdown);
  res.send(html);
});

Такой подход позволяет серверу динамически преобразовывать Markdown в HTML для веб-страниц или API.

Обработка ссылок, изображений и таблиц

Настройки рендерера позволяют кастомизировать генерацию ссылок, изображений и таблиц:

renderer.link = function(href, title, text) {
  return `<a href="${href}" target="_blank" rel="noopener">${text}</a>`;
};

renderer.image = function(href, title, text) {
  return `<img src="${href}" alt="${text}" loading="lazy">`;
};

Использование target="_blank" и rel="noopener" повышает безопасность при открытии внешних ссылок.

Работа с расширениями GitHub Flavored Markdown

Marked поддерживает GFM-специфичные элементы: таблицы, чекбоксы, автоматические ссылки. Пример:

marked.setOptions({ gfm: true });

const markdown = `
- [x] Выполнено
- [ ] В процессе

| Имя | Возраст |
|-----|---------|
| Анна | 25 |
| Борис | 30 |
`;

const html = marked(markdown);

Кэширование рендеринга на сервере

Для больших проектов с повторяющимся контентом имеет смысл кешировать результат рендеринга Markdown в HTML:

const cache = new Map();

function renderMarkdown(markdown) {
  if (cache.has(markdown)) {
    return cache.get(markdown);
  }
  const html = marked(markdown);
  cache.set(markdown, html);
  return html;
}

Это снижает нагрузку на сервер и ускоряет отдачу страниц.

Вывод

Marked обеспечивает высокопроизводительный и гибкий серверный рендеринг Markdown, поддерживает асинхронную обработку, безопасный HTML, кастомизацию рендерера и интеграцию с серверными фреймворками. Продуманное использование токенов, кэширования и опций позволяет создавать масштабируемые и безопасные веб-приложения.