Использование в React

Для работы с библиотекой Marked в проекте на React сначала необходимо установить пакет через npm или yarn:

npm install marked

или

yarn add marked

После установки библиотеку можно импортировать в компонент:

import { marked } from 'marked';

Marked предоставляет функцию marked(), которая принимает строку с Markdown и возвращает HTML. В React важно безопасно вставлять этот HTML, используя dangerouslySetInnerHTML:

function MarkdownRenderer({ content }) {
  const html = marked(content);
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

Настройка опций

Marked позволяет тонко настраивать обработку Markdown через объект опций. Например:

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

Эти параметры можно задавать глобально через marked.setOptions() или локально, передавая объект в функцию marked(content, options).


Кастомизация рендерера

Для сложных случаев можно создавать собственный Renderer, чтобы контролировать, как каждый элемент Markdown преобразуется в HTML. Например:

const renderer = new marked.Renderer();

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

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

function CustomMarkdown({ content }) {
  const html = marked(content, { renderer });
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

Это позволяет добавлять собственные CSS-классы, оборачивать элементы в дополнительные контейнеры или менять поведение ссылок.


Работа с безопасностью

Вставка HTML через dangerouslySetInnerHTML требует осторожности. Чтобы избежать XSS, рекомендуется очищать HTML. Для этого можно использовать библиотеки вроде DOMPurify:

import DOMPurify from 'dompurify';

function SafeMarkdown({ content }) {
  const rawHtml = marked(content);
  const cleanHtml = DOMPurify.sanitize(rawHtml);

  return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}

Такой подход сочетает гибкость Marked и безопасность рендеринга в React.


Интерактивное обновление Markdown

В React удобно интегрировать редактор Markdown с live-просмотром:

import { useState } from 'react';

function MarkdownEditor() {
  const [text, setText] = useState('# Заголовок');

  return (
    <div className="markdown-editor">
      <textarea
        value={text}
        onCha nge={e => setText(e.target.value)}
        rows={10}
        cols={50}
      />
      <div className="preview" dangerouslySetInnerHTML={{ __html: marked(text) }} />
    </div>
  );
}

Этот подход обеспечивает мгновенное преобразование Markdown в HTML при каждом вводе.


Поддержка React Server Components и SSR

При использовании Next.js или других фреймворков с серверным рендерингом (SSR) можно генерировать HTML на сервере:

import { marked } from 'marked';

export async function getServerSideProps() {
  const markdownContent = '# Пример SSR';
  const htmlContent = marked(markdownContent);
  
  return {
    props: { htmlContent }
  };
}

export default function Page({ htmlContent }) {
  return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
}

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


Поддержка синтаксиса GitHub Flavored Markdown

Marked из коробки поддерживает GFM (таблицы, чекбоксы, списки с вложенностью). Для корректного рендеринга можно включить опцию gfm: true и использовать следующие элементы:

- [x] Выполнено
- [ ] В процессе
| Имя | Возраст |
|-----|---------|
| Анна | 28 |
| Борис | 35 |

В React это отобразится корректно при стандартной настройке Marked и добавлении CSS для таблиц и списков.


Поддержка расширений

Marked позволяет добавлять собственные токены и лексеры для расширения синтаксиса Markdown. Например, можно обрабатывать пользовательские блоки:

const lexer = new marked.Lexer();
lexer.rules.customBlock = /^:::(.+)\n([\s\S]+?)\n:::/;

const renderer = new marked.Renderer();
renderer.codespan = (code) => `<code class="highlight">${code}</code>`;

const tokens = lexer.lex(":::note\nПример блока\n:::");
const html = marked.parser(tokens, { renderer });

Это расширяет возможности стандартного Markdown без изменения основной библиотеки.


Интеграция с CSS и стилями

Для красивого отображения Markdown в React используют CSS-модули или styled-components:

.markdown-preview h1 {
  font-size: 2em;
  color: #333;
}

.markdown-preview table {
  border-collapse: collapse;
  width: 100%;
}

.markdown-preview table, .markdown-preview th, .markdown-preview td {
  border: 1px solid #ddd;
  padding: 8px;
}

И подключение стилей к компоненту:

<div className="markdown-preview" dangerouslySetInnerHTML={{ __html: marked(content) }} />

Итоговые рекомендации по производительности

  • При больших объемах Markdown кэшировать результаты marked(content) для снижения лишних пересчетов.
  • Использовать React.memo для компонентов с Markdown-просмотром.
  • Для SSR заранее генерировать HTML, чтобы уменьшить работу на клиенте.

Этот подход позволяет использовать Marked в React максимально гибко: безопасно, с расширениями, кастомными рендерерами и поддержкой серверного рендеринга.