Кроссфреймворковые Web Components для React, Vue и Angular

Когда один интерфейс нужен сразу в нескольких продуктах на разных стеках, команды дублируют разметку, а правки расползаются по релизам. Мы разрабатываем кроссфреймворковые Web Components — единый набор элементов, который одинаково работает в React, Vue и Angular. Изменение выходит один раз и сразу во всех продуктах — время на доработку интерфейсов сокращается в разы.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Кроссфреймворковые Web Components для React, Vue и Angular

Фронтенд-разработка: React, Vue, Next.js, NuxtСложный~5 дней
Часто задаваемые вопросы

Почему Web Components ломаются при встраивании в чужой интерфейс

Компонент, который в изолированной витрине выглядит безупречно, попадает в существующий интерфейс и рассыпается: заголовки наезжают, кнопка теряет отступы, модальное окно уходит под чужой слой. Shadow DOM изолирует правила, но не отменяет наследование: глобальные сбросы и типографика хоста дотягиваются до слотового контента, а через CSS-переменные внутрь протекает тема приложения.

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

Дальше подключается состояние и сборка. Фреймворки передают данные по-разному — строковым атрибутом, свойством или реактивным обновлением, — и часть изменений внутри компонента остаётся для хоста невидимой. Событие из вложенного узла приходит как событие самого компонента, и обработчики срабатывают не там, где их ждут. Две версии одного набора в сборке дают лишний вес и спор о том, чей тег зарегистрировался первым.

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

Что даёт единый набор компонентов на разных стеках

Компонент описывается один раз по веб-стандарту Custom Elements и подключается как обычный тег в React, Vue и Angular — без обёрток под каждый фреймворк. Внутри работает теневой DOM: стили и разметка изолированы, поэтому правило из дизайн-системы не перебивается каскадом приложения. Поверх стандарта удобно взять Lit: декларативные шаблоны и реактивные свойства убирают ручную работу с жизненным циклом элемента.

Единый источник правды меняет экономику правок. Раньше кнопка, поле или таблица жили в трёх репозиториях и расходились при первой же доработке; теперь изменение вносится один раз и приезжает во все интерфейсы одним релизом. Дублирующий код сокращается на треть и больше, а сама правка выпускается в тот же день, а не тремя параллельными задачами.

Контракт взаимодействия тоже становится общим: свойства и события описаны один раз, а не переписываются под пропсы каждого фреймворка. Проверки поведения пишутся против стандарта и не дублируются на три платформы — один набор тестов покрывает все приложения. Отсюда предсказуемость: одинаковое состояние компонента выглядит и ведёт себя одинаково в административной панели, в клиентском кабинете и на лендинге.

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

Способы упаковки и поставки компонентов: сравнение

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

Ниже варианты, между которыми реально выбирают, с ограничениями, которые проявляются не на демо, а на третьем-четвёртом релизе.

Вариант Когда подходит Ограничения
Готовый пакет компонентов Единый набор в нескольких приложениях, обновление централизованное Темы задаются через кастомные свойства; серверный рендеринг требует отдельной поддержки
Обёртка под стек Команды хотят привычный синтаксис, типизацию и автодополнение Обёртку пересобираем на каждый мажор; часть событий и слотов прокидывается вручную
Прямое подключение бандла к странице Встраивание в страницы на старом стеке, контентные системы, лендинги Версии на страницах расходятся, контроля зависимостей нет — совместимость держится вручную
Исходники в общем репозитории Нужны форки и правки под себя Обновления не приезжают сами; версионирование и регресс — на стороне команды

Как удерживаем обратную совместимость

Версионирование компонентов привязываем к контракту, а не к внутренностям: свойства, события, слоты. Мажор меняется только при удалении или смене смысла атрибута, остальное идёт минором. Старые имена продолжают работать один мажорный цикл, поэтому обновление библиотеки в одном сервисе не требует синхронного релиза соседних.

Как мы внедряем библиотеку компонентов: этапы работы

Внедрение библиотеки на web components начинается не с кода, а с инвентаризации продовых интерфейсов. Пока нет карты существующих элементов и расхождений между ними, оценка сроков ничего не стоит. Мы идём фиксированной последовательностью — от аудита до передачи команде.

  1. Аудит интерфейса. Собираем перечень экранов и разбираем существующие элементы по частоте использования, расхождениям в разметке, состояниях и поведении.
  2. Схема компонентов. Фиксируем границы каждого элемента: что уходит в общий набор, что остаётся локальным, какие свойства и события становятся публичным интерфейсом.
  3. Прототип на стыке фреймворков. Собираем один-два компонента и подключаем их в React, Vue и Angular — проверяем, что события, слоты и стили ведут себя предсказуемо в каждом.
  4. Реализация библиотеки. Пишем согласованный набор, закрываем состояния, доступность и тему оформления, настраиваем версионирование и публикацию внутреннего пакета.
  5. Миграция экранов. Заменяем старые реализации поэтапно, по одному маршруту за релиз, с возможностью отката на предыдущую версию интерфейса.
  6. Приёмка результата. Прогоняем поведенческие и визуальные проверки, сверяем с макетами, фиксируем долю покрытых сценариев и список осознанных исключений.
  7. Передача команде. Отдаём репозиторий, документацию, правила релиза и обновления зависимостей, разбираем устройство на живом коде.

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

Что остаётся в проекте: репозиторий, схемы, регламенты

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

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

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

Кейс: как убрали дублирование интерфейсов в четырёх продуктах

Четыре продукта одной компании — кабинет клиента, админ-панель, публичный портал и мобильная веб-версия — развивались разными командами и со временем разошлись в деталях. Ключевые блоки интерфейса — таблицы с сортировкой и постраничным выводом, фильтры, формы, выбор даты, загрузка файлов — существовали в 9–14 копиях каждый.

Точка старта

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

Что сделали

Общие блоки свели в единый слой на Web Components: компонент собирается и проверяется один раз, а в React, Vue и Angular подключается как обычный элемент — без копий разметки, стилей и логики валидации. Стили, поведение и наборы проверок лежат в одном репозитории с одной версией и одним журналом изменений, поэтому один продукт больше не может отстать от остальных в поведении блока.

Показатель До После
Копий одного блока 9–14 1
Репозиториев на одну правку 4 1
Набор проверок на блок свой в каждом продукте общий
Дефекты интерфейса после выпуска около трети единичные

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

Чем Web Components отличаются от обычной библиотеки интерфейсов

Библиотека интерфейсов — это соглашение внутри одного стека: компоненты живут в модели рендеринга конкретного фреймворка и собираются его инструментами. Пока продукт один и стек один, вопроса о переносимости не возникает. Граница видна, когда тот же компонент нужен в другом приложении или в чужом фреймворке.

Web Components переносят договорённости на уровень веб-платформы. Кастомный элемент — обычный тег в разметке, внутреннее устройство закрыто теневым деревом: наружные стили не протекают внутрь, внутренние не влияют на страницу. Изоляцию разметки обеспечивает браузер, а не соглашения и линтеры.

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

Выбор подхода — не про «современность», а про то, где проходит граница между продуктами. Если она внутри одной команды и одного стека, библиотеки достаточно. Если компоненты пересекают границы приложений, изоляцию разумнее делать на уровне платформы.

Частые технические сомнения перед стартом проекта

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

Можно ли внедрять в работающий проект без переписывания?

Да. Компоненты подключаются как обычные теги и не требуют смены сборки: React, Vue и Angular продолжают работать как раньше, а общие элементы живут в одном месте. Начинаем с одного блока — шапки или виджета оплаты — и переносим остальное по мере необходимости. Переписывать весь интерфейс сразу не нужно.

Сможем ли мы поддерживать это своими силами?

Да, если передаём код, проверки и документацию по контрактам элементов: какие атрибуты компонент принимает, какие события отдаёт, что считается ломающим изменением. Знаний за пределами платформы браузера не требуется. Передачу ведём на живом коде, чтобы ваш разработчик сразу вносил правки сам.

Что со старыми браузерами и встроенными представлениями?

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

Как обновлять компоненты, не ломая чужие модули?

Каждый элемент версионируется отдельно и публикуется самостоятельным пакетом, поэтому обновление одного блока не тянет за собой остальные. Контракт — атрибуты, события, слоты — фиксируем и меняем только в мажорной версии, а перед выпуском прогоняем проверки совместимости. Соседние команды переходят на новую версию тогда, когда готовы.

Обсудим задачу и вернёмся с оценкой и планом работ

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

Что полезно приложить к описанию задачи:

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

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

Опишите задачу — вернёмся с оценкой и планом.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1543
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1396
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1375
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1143
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060