Когда шаблонных интерфейсов продукту становится недостаточно, его команда начинает задумываться о внедрении конструктора страниц. Пользователи получают свободу кастомизации, а количество запросов на доработки существенно сокращается.
Но за этими очевидными преимуществами скрывается ряд технических сложностей. Вместе с гибкостью приходят конвертации, конфликты конфигураций, рост стоимости поддержки и потеря контроля над пользовательским интерфейсом.
В этой статье я от лица разработчика платформы событий Saby Meet расскажу о том, как мы внедряли механизм конструирования страниц, с какими ограничениями столкнулись и почему главным вызовом для нашей команды стала не реализация решений на конструкторе, а борьба с хаосом, который неизбежно пришёл в наши лендинги вместе с гибкостью.
Ожидания
Конструктор страниц давно перестал быть инновационным решением. Пользователи привыкли к no‑code инструментам, а возможность самостоятельно проектировать интерфейс со временем стала стандартом для крупных платформ. И мы — не исключение.
Знакомьтесь, Saby Meet — онлайн‑сервис для работы, коммуникаций, продаж, собеседований и обучения. Один из ключевых сценариев продукта — проведение встреч, требования к оформлению которых могут сильно различаться в зависимости от их контекста. Со временем шаблонных решений стало недостаточно для удовлетворения пользовательских потребностей.

Базовый механизм для конструирования страниц уже существовал в экосистеме Saby и разрабатывался отдельной командой. Это позволило нам сосредоточиться не на механиках создания лендингов встреч, а на адаптации их под новую модель.
На первый взгляд, решение казалось удачным: пользователи получали свободу кастомизации страниц, а наша команда — сокращение количества запросов на доработку интерфейса. Однако этот шаг обернулся рядом трудностей.
Реальность
На практике конструктор не упростил поддержку, а лишь перераспределил нагрузку команды.
Действительно, клиентам больше не требуется обращаться к разработчикам за каждой доработкой интерфейса. Теперь значительную часть задач решает конструктор сайтов. Но вместе с гибкостью в продукт пришла новая проблема — поддержка пользовательских конфигураций.
Каждый лендинг представляет собой разметку страницы, собранную пользователем. У каждой встречи собственная конфигурация. Событий в системе — десятки тысяч. Любое изменение интерфейса или контракта данных элемента страницы потенциально влияет на уже существующие лендинги. Добавление нового компонента, изменение его параметров или удаление могут потребовать массовой миграции конфигураций.
Проверять совместимость каждой страницы вручную — невозможно. Всё, что нам остается — создавать универсальные алгоритмы конвертации.
Становится очевидно, что полной свободы кастомизации не существует. Любой конструктор ограничен архитектурой платформы, требованиями безопасности, производительности и бизнес‑логикой продукта.

Некоторые ограничения закономерны:
Технические нюансы — ограничения, обусловленные платформой, устройствами и стеком используемых технологий.
Безопасность — защита от выполнения вредоносного кода и утечек данных.
Производительность — лимиты размера страницы, технические и поведенческие метрики.
Другие ограничения проявляются в процессе эксплуатации системы:
Поведенческие — условия пользовательских сценариев. Например, нельзя купить билет на прошедшее событие.
Контекстные — ограничения, обусловленные типом события. Например, лендинг офлайн‑мероприятия не может содержать элементы онлайн‑трансляции.
Но наиболее явные нам пришлось установить самостоятельно:
Структурные ограничения — правила компоновки, регулирующие конфигурацию страницы.
Дизайн — палитры цветов и шрифтов, обеспечивающие визуальную целостность лендинга.
Операционные нюансы — эксплуатационные ограничения, связанные с поддержкой, миграциями, масштабированием и совместимостью конфигураций.
В этот момент мы пришли к выводу: свобода пользователя — это не отсутствие ограничений. Это пространство, которое нужно проектировать и контролировать.
Решение
Конфигурация
С внедрением конструктора интерфейс лендинга встречи перестаёт быть статичным набором компонентов. Теперь его структура — самостоятельная сущность, описываемая в декларативной форме. Такой подход соответствует парадигме Configuration Driven Development (CDD), в которой интерфейс лендинга определяется его конфигурацией.
Пример упрощенной конфигурации страницы встречи:
[ "frame", {}, [ "Widgets/title:View", { "size": "m" } ], [ "Widgets/speakers:View", { "photoSize": "m", "hasDescription": true } ] ]
Архитектура конструктора страниц уже была представлена в экосистеме Saby набором сущностей, необходимых для построения лендинга:
Конструктором — конфигурацией редактора,
Страницей — композицией лендинга,
Темой — палитрой цветов и шрифтов события.
Все они хранятся в формате JSON и формируют каркас страницы, наполненный виджетами.

Виджеты
Основной единицей на странице стал виджет — изолированный React‑компонент, обладающий набором метаданных, необходимых для интеграции с конструктором: название, описание, редакторы, значения по умолчанию и прочие параметры.
Изоляция виджета — ключевое ограничение. Компонент не должен зависеть от контекста события или структуры страницы, что позволяет обеспечить свободу переиспользования виджета между сценариями и сохранить контроль над ним по мере развития платформы.
Данные
Изоляция виджетов закономерно повлияла на требования к модели данных страницы.
Теоретически каждый элемент мог бы самостоятельно загружать данные с сервера. В реальности же лендинг события представляет собой единый интерфейс, в котором один и тот же набор данных используется несколькими виджетами одновременно.
В связи с этим мы решили обеспечить централизацию состояния встречи через единую View Model, которая формирует набор данных для каждого отдельного виджета. Такое решение позволяет не только сократить количество запросов на сервер, но и синхронно обновлять состояние лендинга во время проведения встречи.
Реализация
Переход к декларативной форме описания страниц неизбежно привел к появлению ограничений на уровне реализации. Новая модель лендингов повлияла преимущественно на устройство виджетов, поддержку конфигураций и рендеринг страниц.
Виджеты
В классическом интерфейсе компоненты располагаются в предсказуемом окружении: разработчик самостоятельно формирует композицию страницы, положение элементов на ней и пользовательские сценарии.
В контексте конструктора невозможно спрогнозировать структуру и контент лендинга, которые определит пользователь. Поэтому требования к виджетам на странице существенно меняются.
Контент
Виджет не может полагаться на фиксированные размеры или стабильное положение на странице. Его габариты определяются пользовательской конфигурацией.
На практике это означает, что любые жесткие ограничения размеров виджета неизбежно приведут к ошибкам: переполнению контента, дефектам верстки или некорректному отображению на отдельных устройствах.
В результате нам пришлось спроектировать виджеты максимально независимыми от их окружения и габаритов.
Интерактивность
Несмотря на то, что изоляция обеспечила удобство переиспользования виджетов, она лишила их возможности «знать» о присутствии друг друга на странице. Например, несколько элементов могут независимо открывать всплывающие окна или управлять состоянием лендинга.
Это потребовало от нас централизовать не только данные, но и обработчики действий пользователя. Иначе интерфейс неизбежно столкнулся бы с коллизиями состояния и непредсказуемым поведением страницы.
Контракт
В контексте декларативного описания страниц любое изменение набора параметров виджета влияет не только на код компонента, но и на существующие конфигурации лендингов.
По этой причине мы старались сделать контракты виджетов максимально гибкими и по возможности избегать записи избыточных свойств в конфигурацию страницы. В особенности, значений по умолчанию. В противном случае любое изменение интерфейса со временем вызывало бы проблемы совместимости и миграции конфигураций.
Конфигурации
С внедрением конструктора конфигурации, которые создает пользователь, фактически становятся частью системы. Их поддержку необходимо воспринимать как обслуживание публичного API, что существенно влияет на стоимость изменений в интерфейсе.
Совместимость
При декларативном описании страниц изменение виджета влияет не только на его реализацию, но и на пользовательские конфигурации. Даже небольшие правки, такие как изменение UI компонента, его свойств или положения на странице могут потребовать конвертации десятков тысяч опубликованных лендингов.
Например, оригинальный контракт виджета ведущих:
{ "photoSize": "m", "hasDescription": true }
Со временем превращается в:
{ "photo": { "size": "m", "rounded": true }, "sections": [ "position", "company", "description" ] }
В такой ситуации команда разработки встает перед выбором: поддерживать обратную совместимость виджетов или регулярно выполнять конвертации пользовательских конфигураций.
Становится очевидно, что даже незначительное расширение функционала может увеличить стоимость поддержки системы. Иными словами, любое «да» для пользователя сегодня превращается в поддержку для команды завтра.
Контроль
После публикации лендинга разработчик перестает контролировать структуру страницы. Любое изменение интерфейса со стороны команды разработки может нарушить пользовательскую конфигурацию.
Мы решили отказаться от концепции «полной свободы» и ограничить пользователю набор доступных инструментов конструирования. Новые возможности договорились внедрять по принципу whitelist: только надежные решения, работоспособность и совместимость которых мы можем гарантировать на протяжении долгого времени. Именно эти ограничения в дальнейшем позволили нам сохранить контроль над интерфейсом.
Рендеринг
Некоторое количество ограничений появилось на этапе построения страницы в связи с тем, что лендинг встречи должен быть:
индексируемым,
адаптивным,
интерактивным,
производительным.
Эти критерии обусловили подход к рендерингу страницы.
SEO и SSR
Лендинг — это страница, которая не только отображает интерфейс события, но и участвует в поисковой индексации.
Поисковым системам критически важно получать готовый HTML‑код еще на этапе загрузки страницы. Поэтому мы были вынуждены внедрить механизм Server Side Rendering (SSR), который значительно повлиял на устройство виджетов.
Во‑первых, мы столкнулись с необходимостью отказаться от большинства скелетонов и загрузчиков для критически важного Search Engine Optimization (SEO) контента. Ключевая информация о встрече должна быть сформирована на этапе серверного рендеринга.
Во‑вторых, сервер не может надежно определить габариты и положение виджетов на странице, так как они зависят от параметров устройства пользователя и размеров окна браузера. Это существенно усложнило подход к адаптивной вёрстке интерфейса.
Modern CSS
Часть проблем, связанных с вёрсткой, нам удалось решить средствами современного CSS, последние обновления которого расширили возможности адаптации интерфейса под размеры и содержимое контейнеров.
Наиболее эффективными оказались container queries и селектор:has, позволяющие элементам реагировать не только на размеры области просмотра, но и на габариты виджета и его контент.
Например, так выглядят упрощённые стили виджета ведущих:
.speakers { container-type: inline-size; } .speakers__list { display: flex; } .speakers__show-all { display: none; } /* Список ведущих адаптируется под размер виджета */ @container (max-width: 300px) { .speakers__list { flex-direction: column; } } /* Показываем кнопку, если ведущих 3 или более */ .speakers:has(.speakers__item:nth-child(n + 3)) .speakers__show-all { display: block; }
Modern CSS помог нам частично компенсировать ограничения SSR. Вместо вычисления размеров и положения виджетов на сервере мы перенесли значительную часть адаптивной логики на клиент. Это позволило нам сохранить гибкость конфигурации лендингов без усложнения механизма серверного рендеринга.
Critical Rendering Path
Финальным этапом технической реализации стала оптимизация производительности лендинга.
В классическом интерфейсе разработчик самостоятельно формирует структуру страницы и может явно определить, какой контент является критическим для первой отрисовки. В контексте конструктора такая возможность практически отсутствует, так как пользователь самостоятельно собирает страницу. Спрогнозировать порядок расположения элементов на странице заранее невозможно, в частности из‑за адаптивной верстки, что усложняет оптимизацию Critical Rendering Path (CRP).
В связи с этим мы отказались от принудительного выделения критически важных виджетов на странице, так как их значимость напрямую зависит от пользовательской конфигурации. Вместо этого мы сделали акцент на снижении времени первого взаимодействия со страницей. Для этого мы:
произвели code splitting для TypeScript и Less бандлов,
добавили ленивую загрузку скрытого контента,
сократили объем клиентских модулей,
уменьшили количество блокирующих скриптов,
оптимизировали рендеринг React‑компонентов и количество лишних перерисовок.
Результат
Мы внедрили в платформу событий не просто набор настраиваемых шаблонов, а полноценную систему конструирования страниц. Теперь пользователи могут самостоятельно собирать лендинги встреч, не прибегая к помощи разработчиков или сторонних сервисов.

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

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