Автосохранение

Библиотека Marked является одним из самых популярных инструментов для парсинга Markdown в JavaScript. Она позволяет конвертировать текст, написанный в Markdown, в HTML с высокой скоростью и гибкостью настройки. Основной принцип работы заключается в разборе исходного Markdown-текста на токены и последующей генерации HTML через встроенный рендерер.

import { marked } from 'marked';

const markdown = '# Заголовок\n\nТекст с **жирным выделением**.';
const html = marked(markdown);
console.log(html);

В этом примере строка Markdown преобразуется в HTML с корректными тегами

и .


Настройка и использование рендереров

Marked позволяет задавать собственные рендереры для управления формированием HTML. Это удобно, когда требуется кастомное отображение элементов.

const renderer = {
  heading(text, level) {
    return `${text}`;
  },
  link(href, title, text) {
    return `${text}`;
  }
};

marked.use({ renderer });
  • heading – позволяет добавлять классы и атрибуты к заголовкам.
  • link – позволяет изменять поведение ссылок, например, открывать их в новом окне.

Опции парсинга

Marked поддерживает множество опций, которые влияют на обработку текста:

  • gfm – включает поддержку расширенного синтаксиса GitHub Flavored Markdown (таблицы, чекбоксы, автоссылки).
  • breaks – заменяет обычные переносы строк на
    .
  • sanitize – устаревшая опция, используемая для предотвращения XSS, лучше использовать DOMPurify для очистки HTML.
  • smartLists – улучшает обработку списков с вложенностью.
marked.setOptions({
  gfm: true,
  breaks: true,
  smartLists: true
});

Лексический и синтаксический разбор

Marked разделяет процесс обработки на два этапа:

  1. Лексический анализ (Lexer) – разбивает текст на токены, определяет тип элементов: заголовок, абзац, список, код и др.
  2. Синтаксический разбор (Parser) – преобразует токены в HTML, используя рендерер.
const lexer = new marked.Lexer();
const tokens = lexer.lex('# Пример\n\nСписок:\n- пункт 1\n- пункт 2');

const parser = new marked.Parser();
const html = parser.parse(tokens);
console.log(html);

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


Расширение функциональности через плагины

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

const tokenizer = {
  paragraph(src) {
    const match = src.match(/:::(\w+)\n([\s\S]+?)\n:::/);
    if (match) {
      return {
        type: 'customBlock',
        name: match[1],
        text: match[2],
        raw: match[0]
      };
    }
  }
};

const renderer = {
  customBlock(token) {
    return `
${token.text}
`; } }; marked.use({ tokenizer, renderer });

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


Работа с безопасным HTML

Для предотвращения XSS важно фильтровать результат работы Marked:

import DOMPurify from 'dompurify';

const rawHTML = marked(markdown);
const cleanHTML = DOMPurify.sanitize(rawHTML);

DOMPurify обеспечивает безопасный HTML для вставки в DOM и работает корректно с любыми опциями Marked.


Автосохранение Markdown

Автосохранение часто требуется при работе с редакторами Markdown. Простейший подход – сохранять текст в localStorage при каждом изменении:

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

textarea.addEventListener('input', () => {
  localStorage.setItem('markdownContent', textarea.value);
});

Для восстановления состояния при перезагрузке:

const saved = localStorage.getItem('markdownContent');
if (saved) {
  textarea.value = saved;
}

Для более продвинутого автосохранения можно использовать дебаунс – сохранение каждые несколько секунд, чтобы не перегружать хранилище:

let timeout;
textarea.addEventListener('input', () => {
  clearTimeout(timeout);
  timeout = setTimeout(() => {
    localStorage.setItem('markdownContent', textarea.value);
  }, 1000);
});

Встраивание Markdown в динамический HTML

Markdown можно обновлять в реальном времени, используя input и динамическое преобразование в HTML:

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

textarea.addEventListener('input', () => {
  const html = marked(textarea.value);
  preview.innerHTML = DOMPurify.sanitize(html);
});

Такое решение обеспечивает интерактивный редактор с автосохранением и безопасным отображением контента.