Олег Карнауховweb developerОбсудить проект

Блог

Блочный редактор вместо Markdown: почему у моего блога нет разметки в тексте

Markdown — очевидный выбор для блога. Я его не взял, и вот честный разбор: что теряется, что выигрывается и почему две модели контента хуже одной.

Когда я добавлял блог к существующему сайту, самым быстрым путём был Markdown: поле, парсер, готово. Я выбрал блоки — те же, из которых собраны все остальные страницы. Решение неочевидное, поэтому объясняю.

Одна модель контента вместо двух

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

Через полгода это чинится по очереди: поправил в блоках — забыл в статьях. Одна модель дороже на входе и дешевле всё остальное время.

Текст в полях — простой текст, и это защита

Абзацы у меня рендерятся как обычный текст, без разбора разметки. Значит, ничего, набранное в поле, не может внедрить теги. Обратная сторона: ссылку в тексте поставить нельзя — и это заметное ограничение, ради которого пришлось завести отдельный блок ссылок.

Звучит как костыль, но у него есть свойство: все адреса, куда ведёт статья, — это поля, а не строчки внутри прозы. Их видно списком, их легко проверить.

ЧтоMarkdownБлоки
Порог входанижевыше
Вёрстка сложногонужен HTML внутриблок под задачу
Картинкипуть рукамимедиатека и выбор
Безопасностьнужен санитайзертекст остаётся текстом
Переиспользованиетолько в статьяхна любой странице
Markdown выигрывает только в одной строке — и это строка про первый час работы, а не про год.

Блок кода: почему без подсветки

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

Подсветка требует токенизатора. Токенизатор на регулярках ошибается предсказуемо: незакрытая строка съедает половину файла, ключевое слово находится внутри имени переменной. Неправильно подсвеченный код в статье про код хуже одноцветного — он врёт о структуре того, что читатель пытается понять.

Поэтому блок делает то, что нельзя сделать неправильно: имя файла, язык подписью, номера строк, которые не попадают в выделение, и кнопка «скопировать», отдающая код без отступов, унаследованных от чужого файла.

app/content/code.tsts
/** Строки фрагмента, с убранным общим отступом.
    Самая неглубокая строка решает, сколько снять, — форма фрагмента выживает. */
export function lines(code: string): string[] {
  const rows = code.replace(/\s+$/, "").split("\n");
  const indents = rows
    .filter((row) => row.trim().length > 0)
    .map((row) => row.length - row.trimStart().length);

  const common = indents.length ? Math.min(...indents) : 0;
  return rows.map((row) => row.slice(common));
}
Код, скопированный из середины файла, приезжает с отступом того файла. Блок снимает общий отступ и оставляет относительный.