Режим предпросмотра в реальном времени

Библиотека Marked предоставляет высокопроизводительный парсер Markdown в JavaScript и позволяет мгновенно преобразовывать текст в HTML. В режиме предпросмотра в реальном времени ключевым моментом является обеспечение синхронного рендеринга текста по мере его ввода.

Для базового преобразования используется функция marked.parse или её сокращённая форма marked(). Пример минимального использования:

import { marked } from 'marked';

const markdownText = "# Заголовок\n\nЭто пример текста.";
const html = marked(markdownText);

console.log(html);

Результат:

<h1>Заголовок</h1>
<p>Это пример текста.</p>

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

Marked поддерживает широкие возможности настройки через объект options, который можно передать при инициализации. Ключевые параметры:

  • gfm — включение GitHub Flavored Markdown (по умолчанию true).
  • breaks — автоматический перенос строк при новой строке (false по умолчанию).
  • sanitize — удаление потенциально опасного HTML (устаревший параметр; рекомендуется использовать DOMPurify для безопасного HTML).
  • mangle — защита e-mail адресов от спам-ботов.
  • headerIds — автоматическое добавление id для заголовков (true по умолчанию).
  • langPrefix — префикс для подсветки синтаксиса кода.

Пример:

marked.setOptions({
  gfm: true,
  breaks: true,
  headerIds: true,
  langPrefix: 'language-'
});

Подключение режима предпросмотра

Для реализации живого предпросмотра используется событие ввода на элементе <textarea> и динамическая вставка HTML в контейнер:

const textarea = document.getElementById('editor');
const preview = document.getElementById('preview');

textarea.addEventListener('input', () => {
  const markdownText = textarea.value;
  preview.innerHTML = marked.parse(markdownText);
});

Ключевой момент: каждое изменение текста триггерит пересборку HTML, что обеспечивает мгновенный отклик. Для больших документов рекомендуется добавлять дебаунсинг ввода, чтобы уменьшить нагрузку на парсер:

let debounceTimer;
textarea.addEventListener('input', () => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    preview.innerHTML = marked.parse(textarea.value);
  }, 200);
});

Настройка рендерера для кастомного HTML

Marked позволяет переопределять стандартный рендеринг через объект Renderer. Это особенно полезно для добавления классов CSS или обработки нестандартных элементов Markdown.

const renderer = new marked.Renderer();

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

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

marked.setOptions({ renderer });

Теперь все заголовки и ссылки будут использовать кастомное оформление, сохраняя при этом полное соответствие стандарту Markdown.

Поддержка синтаксиса кода и подсветки

Для полноценного предпросмотра важно корректно обрабатывать блоки кода. Marked поддерживает передачу функции подсветки через highlight:

import hljs from 'highlight.js';

marked.setOptions({
  highlight: function(code, lang) {
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(code, { language: lang }).value;
    }
    return hljs.highlightAuto(code).value;
  }
});

Блоки кода <pre><code> будут автоматически подсвечиваться, что делает предпросмотр более информативным и визуально структурированным.

Использование кастомных токенов

Для расширенных сценариев можно использовать токены Markdown напрямую. Например, добавление нестандартного блока заметки:

const tokenizer = {
  blockquote(src) {
    const match = src.match(/^::note\s+([\s\S]+?)::/);
    if (match) {
      return {
        type: 'blockquote',
        raw: match[0],
        text: match[1].trim(),
        tokens: this.lexer.inlineTokens(match[1].trim())
      };
    }
    return false;
  }
};

marked.use({ tokenizer });

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

Оптимизация производительности

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

  1. Дебаунсить события ввода, чтобы уменьшить частоту вызовов marked.parse.
  2. Кэшировать результат, если текст не изменился.
  3. Разделять длинный текст на секции, чтобы рендерить только видимую часть.
  4. Использовать Renderer для оптимизированного HTML, минимизируя лишние вложенные элементы.

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

  • Для быстрой обратной связи — парсить Markdown при каждом вводе.
  • Для больших документов — вводить дебаунсинг и ленивый рендеринг.
  • Для кастомного оформления — использовать собственный Renderer.
  • Для безопасного HTML — применять внешние библиотеки очистки, такие как DOMPurify.

Такой подход позволяет создавать полноценный режим предпросмотра в реальном времени, сочетающий высокую производительность и гибкость настройки.