- PVSM.RU - https://www.pvsm.ru -
Практический разбор создания и развития собственной UI-библиотеки
Коротко: Собственная UI-библиотека — это не только набор React-компонентов. После появления нескольких проектов-потребителей на первый план выходят API, состояние, совместимость, зависимости, тестирование, документация и версионирование.
Когда в проекте начинает появляться всё больше одинаковых элементов интерфейса, рано или поздно возникает вопрос: зачем каждый раз создавать один и тот же Button, Input или Select?
Мы рассматривали готовые решения, в том числе Ant Design и Material UI, но они не закрывали наши требования. Нам требовался больший контроль над внешним видом и поведением компонентов, возможность детально адаптировать их под наши задачи и учитывать требования проекта к безопасности.
Поэтому мы решили сделать собственную UI-библиотеку. Первая версия заняла примерно месяц — вместе с макетами, разработкой, настройкой сборки и тестами.
React
TypeScript
CSS Modules
Webpack
Unit-тесты
На старте было шесть компонентов:
Input
Select
Drawer
Badge
Table
Layout — базовая обёртка для построения интерфейса
Для каждого компонента были предусмотрены тесты. Сейчас библиотека выросла до 30+ компонентов. Среди них есть сложные составные элементы — например, фильтр и календарь с выбором дат и времени в разных форматах.

Первые компоненты решали достаточно конкретные задачи. Но по мере развития продукта стали появляться элементы, которые объединяют несколько контролов, popup-элементов и собственную логику. В этот момент становится понятно, что UI Kit — уже не просто коллекция компонентов. Это отдельный программный продукт со своим API, тестами, документацией, версиями и жизненным циклом.
Одна из главных ошибок — попытка сделать компонент максимально универсальным. На бумаге кажется логичным: если компонент умеет больше, его можно использовать в большем количестве мест.
На практике часто происходит наоборот. Чем больше логики появляется внутри компонента, тем сложнее его изменить, протестировать и адаптировать под конкретный сценарий.
Особенно это заметно на составных компонентах. Фильтр может включать несколько контролов, собственное состояние, кнопки применения и сброса, popup-элементы и дополнительную логику взаимодействия.
Практический вывод: Не стоит пытаться сделать один компонент решением абсолютно всех задач. Иногда лучше дать разработчику набор небольших компонентов и возможность собрать нужный сценарий самостоятельно.
Одна из проблем переиспользуемых компонентов — неправильная организация состояния. Представим, что на разных страницах приложения есть Select с фильтрами. Открытие Select на странице A не должно влиять на Select на странице B.

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

Каждому popup необходимо правильно определить положение относительно элемента, который его открыл. Если механизм позиционирования недостаточно изолирован, один popup может начать влиять на другой.
Причём отдельно Select, DatePicker и Dropdown могут работать нормально, а проблема появляется только при их совместном использовании внутри сложного компонента. Поэтому такие сценарии важно тестировать не только по отдельности, но и в комбинациях, близких к реальному использованию.
На каждый компонент нашего UI Kit есть тесты. Но наличие теста само по себе не гарантирует отсутствие проблем. Компонент может пройти unit-тесты и при этом визуально сломаться после изменения CSS или вести себя иначе в составе сложного компонента. Поэтому важно разделять две вещи: «код работает» и «компонент корректно работает во всех местах, где его используют».
Самый неприятный случай произошёл с Drawer. Мы внесли изменения в компонент, выпустили новую версию UI Kit, после чего обновили её в проектах. После обновления разметка Drawer уехала.

Почему это больно: Ошибка в локальном компоненте затрагивает одну страницу.
Ошибка в общей библиотеке может затронуть сразу несколько проектов после обновления версии.
Получилась цепочка: изменение Drawer → новая версия UI Kit → обновление версии в проектах → изменение поведения Drawer → проблема во всех проектах.
Именно здесь особенно хорошо видно отличие UI Kit от обычного компонента внутри приложения. Внутри приложения ошибку можно быстро исправить и задеплоить. В библиотеке ошибка становится частью версии, которую могут использовать несколько независимых приложений.
Поэтому любое изменение общего компонента необходимо рассматривать не только с точки зрения самого компонента. Нужно задать вопрос: «Что произойдёт со всеми потребителями этой библиотеки?»
UI Kit не существует в вакууме. У него есть React, TypeScript и другие зависимости. Если несколько приложений используют одну библиотеку, обновление её зависимостей может стать отдельной задачей.
Особенно это заметно в микросервисной архитектуре, где разные приложения могут иметь собственные циклы релизов. Если общий пакет начинает жёстко диктовать версии зависимостей, обновление может превратиться в цепочку изменений сразу в нескольких проектах.
Практический вывод:Общие пакеты стоит проектировать с учётом границ ответственности за зависимости: какие версии поддерживаются, что является peer dependency, как проверяется совместимость и как выпускаются breaking changes.
Когда компонент пишет его автор, большая часть API кажется очевидной. Но через несколько месяцев библиотекой пользуется другой разработчик.
<Button
variant="primary"
size="large"
loading
>
Сохранить
</Button>
Без документации разработчику приходится открывать исходный код, чтобы понять варианты, обязательные props, состояния и ограничения.
что делает компонент;
какие props он принимает;
какие значения поддерживаются;
какие значения используются по умолчанию;
какие есть ограничения;
какие есть реальные сценарии использования.
Главный принцип: Документация — не приложение к UI Kit. Это часть самого продукта.
Создавая собственную библиотеку, легко попасть в ловушку: «раз это наша библиотека, всё должно быть написано нами с нуля». Но даже если Ant Design или Material UI не подходят целиком, их решения стоит изучать.
как похожая задача решена в других библиотеках;
какой API они используют;
как устроено управление состоянием;
как решено позиционирование popup;
какие edge cases они учитывают;
какие ограничения есть у их подхода.
Не обязательно копировать реализацию. Гораздо разумнее взять проверенную концепцию и адаптировать её под свои требования.
Однозначного ответа нет. Выбор зависит не от того, какая библиотека «лучше», а от требований конкретного продукта.
|
Критерий |
Готовая библиотека |
Собственный UI Kit |
Что важно |
|
Скорость старта |
Высокая |
Ниже |
Для MVP и внутренних систем готовое решение часто выгоднее |
|
Контроль UI |
Зависит от API |
Максимальный |
Свой дизайн и поведение легче контролировать |
|
Поддержка |
Есть экосистема |
На команде |
Свой UI Kit требует постоянного сопровождения |
|
Несколько проектов |
Зависит от настройки |
Удобно |
Особенно если есть общая дизайн-система |
|
Цена ошибки |
Обычно ниже |
Может быть высокой |
Общая библиотека влияет на всех потребителей |
Если задача — быстро собрать внутреннюю админку, CRM или MVP, я бы в первую очередь посмотрел на готовые решения. Они дают большой набор компонентов и экономят время на базовой инфраструктуре.
Собственная библиотека начинает иметь смысл, когда требования проекта заметно выходят за рамки готового решения: нужен полностью свой дизайн, специфическое поведение, единая система компонентов для нескольких проектов или полный контроль над API.
|
Наш выбор: Если требования проекта останутся такими же, мы, скорее всего, снова выберем собственный UI Kit. Но сегодня подошли бы к его созданию осторожнее: заранее продумали бы границы компонентов, состояние, API, зависимости, совместимость, документацию, тестирование и стратегию версионирования. |

Главное изменение произошло даже не в количестве компонентов. Изменилось наше отношение к библиотеке.
В начале мы воспринимали UI Kit как набор переиспользуемых компонентов. Теперь это отдельный продукт, у которого есть API, версии, зависимости, тесты, документация, проекты-потребители, обратная совместимость и собственный жизненный цикл.
Сначала изучил бы существующие решения — не нужно изобретать всё самостоятельно.
Не делал бы компоненты слишком универсальными — компонент должен решать задачу, но не предусматривать все возможные сценарии.
С самого начала продумал бы состояние — особенно для интерактивных компонентов.
Считал бы документацию частью разработки — компонент без понятного API и примеров сложно считать законченным.
Тестировал бы не только компоненты, но и их комбинации — особенно сложные составные компоненты.
Осторожнее относился бы к breaking changes — если библиотеку используют несколько проектов, изменение одного компонента может затронуть всю систему.
Создать первый UI Kit оказалось не так сложно. Первую версию мы сделали примерно за месяц.
Самое интересное началось после этого. Шесть компонентов превратились в тридцать с лишним. Появились сложные составные компоненты, собственные сценарии взаимодействия, зависимости, версии и несколько проектов, использующих одну библиотеку.
И вместе с ростом библиотеки изменились сами проблемы.
Главный урок: В начале главный вопрос был: «Как сделать этот компонент?»
Позже вопрос стал другим: «Как изменить этот компонент так, чтобы не сломать всё, что уже использует нашу библиотеку?»
UI-библиотека — это не набор красивых компонентов. Это отдельный продукт, который нужно проектировать с расчётом на развитие, совместимость и будущих пользователей.
И чем больше проектов её используют, тем дороже становится каждая архитектурная ошибка.
Автор: Goker1235
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ui/457672
Ссылки в тексте:
[1] Источник: https://habr.com/ru/articles/1080784/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1080784
Нажмите здесь для печати.