CMS и управление контентом: WYSIWYG, медиабиблиотека, галереи
Редактор на сайте — это интерфейс, которым пользуются каждый день люди, не имеющие отношения к разработке. Если в нём неудобно менять заголовок статьи, не работает загрузка изображений или форматирование сбивается при копировании из Word — контент либо не обновляется, либо обновляется с ошибками. Это прямые потери: устаревшие цены, неактуальные акции, SEO-тексты, которые никто не правит.
Выбор CMS: когда что подходит
Headless CMS (Strapi, Contentful, Sanity) отделяет управление контентом от фронтенда. Контент через API потребляет любой клиент: веб-сайт, мобильное приложение, цифровые вывески. Правильный выбор для омниканальных продуктов и когда фронтенд на React/Vue/Next.js.
Sanity выделяется кастомизируемой Studio: каждое поле, каждый тип документа, каждый виджет — React-компонент, который можно заменить. Portable Text (их формат для rich content) портируется в любой рендерер. Для сложных редакторских workflow — лучший выбор в своей категории.
Contentful — стабильный облачный сервис, большой marketplace расширений, хорошая CDN для медиафайлов. Минус — цена при росте объёма контента.
Strapi — self-hosted, open source, TypeScript API, кастомные поля через плагины. Хостишь сам, данные твои.
Традиционный CMS (WordPress, Craft CMS, Statamic) — когда нужен привычный редакторский интерфейс и нет отдельного фронтенд-проекта. Craft CMS — профессиональный инструмент для контент-команд: Matrix поля, гибкая структура записей, встроенная локализация.
Встроенный в Laravel (Nova, Filament): когда приложение уже на Laravel и нет смысла добавлять отдельную CMS. Filament — современный, React+Livewire, богатая экосистема плагинов.
WYSIWYG: Tiptap, Lexical, TinyMCE
Редактор — это отдельная инженерная задача, не просто <textarea>.
Tiptap (обёртка над ProseMirror) — лучший баланс кастомизируемости и удобства. Каждый элемент редактора — расширение: заголовки, списки, таблицы, упоминания, блоки кода — добавляются выборочно. Collaborative editing через Yjs — встроено. Для Next.js/React-проектов — первый выбор.
Lexical (Meta, open source) — высокопроизводительный, extensible, написан для Facebook. Сложнее в настройке чем Tiptap, но мощнее в кастомизации. Подходит если нужны нестандартные блоки.
TinyMCE — многолетний стандарт для корпоративных CMS. Работает из коробки, знаком многим редакторам. Минус — устаревший API, тяжеловат по бандлу (~300KB), меньше контроля над структурой контента.
Проблема всех WYSIWYG: «грязный» HTML при вставке из Word. вместо пробелов, inline-стили на каждом теге, вложенные <span> без смысла. Sanitize на вставку обязателен — иначе вёрстка ломается, SEO страдает.
Медиабиблиотека
Загрузка файлов через простой <input type="file"> с прямым сохранением на диск сервера — антипаттерн. Диск заполнится, масштабирование невозможно, CDN не подключишь.
Правильная схема: загрузка в S3-совместимое хранилище (AWS S3, Cloudflare R2, MinIO для self-hosted) → CDN поверх (CloudFront, Cloudflare) → трансформации по запросу.
Imgproxy или Thumbor для серверной трансформации изображений: один оригинальный файл, любые размеры и форматы генерируются динамически. URL несёт параметры: https://img.example.com/resize:800:600/format:webp/plain/s3://bucket/photo.jpg. Оригинал хранится один раз, производные не нужно хранить.
Cloudflare Images — managed сервис: загружаешь оригинал, получаешь вариантные URL для разных размеров. $5 за 100k изображений с трансформациями — часто дешевле self-hosted.
Для видео: Cloudflare Stream или Mux. Загружаешь исходник, платформа кодирует в HLS, отдаёт адаптивный стриминг. Без этого видео файл весит 500MB и загружается как есть.
Организация галерей
Drag-and-drop сортировка в галерее — базовое требование. @dnd-kit/sortable (React) или SortableJS — библиотеки с accessibility-поддержкой. Сортировка через целочисленный order в базе данных: при каждой перестановке пересчитываются order значения только затронутых элементов.
Ленивая загрузка изображений в галерее обязательна. loading="lazy" на <img> для нативной ленивой загрузки. Intersection Observer API для кастомного контроля. На галерее 200 фотографий без lazy loading — 150MB трафика при открытии страницы.
Lightbox: Photoswipe или Glightbox — доступные, без jQuery, с touch-жестами и keyboard-навигацией.
Структурированный контент vs free-form HTML
Free-form WYSIWYG создаёт непредсказуемый HTML. Через год контент-менеджер поставил 7 разных размеров шрифта, 12 цветов, случайные отступы. Редизайн невозможен без ручной чистки каждой страницы.
Структурированный контент: вместо «как оно выглядит» — «что это есть». Не <p style="font-size:24px; color:red">Важно!</p>, а тип блока callout с параметром variant: warning. CMS хранит структуру, фронтенд решает как её рендерить.
Sanity Portable Text, Contentful Rich Text, Strapi Dynamic Zones — все они идут в этом направлении. Переход с free-form HTML на structured content при миграции — трудоёмкая задача, но окупается при следующем редизайне.
Процесс работы
Начинаем с аудита редакторских сценариев: кто редактирует, как часто, какой контент, нужна ли локализация. Выбор CMS под сценарии, а не по трендам. Настройка прав доступа, workflow для публикации (черновик → на проверке → опубликован), интеграция с CDN для медиафайлов.
Сроки
Интеграция headless CMS (Strapi/Sanity) в существующий Next.js проект: 2–5 недель. Кастомный WYSIWYG-редактор с Tiptap и специфичными блоками: 2–4 недели. Медиабиблиотека с S3 + трансформации: 1–3 недели. Полная CMS-система с нуля: 4–10 недель.







