Частая ситуация: в компании пять фронтенд-приложений, а Button в каждом выглядит по-своему. Это не просто эстетическая проблема — раздутый bundle, дублирование кода и сложный онбординг новых разработчиков. Компонентная библиотека решает всё это разом.
Мы разрабатываем компонентную библиотеку — набор UI-компонентов с единым стилем, поведением и API, который устанавливается как npm-пакет (npm install @company/ui). В отличие от простой папки components в монолите, это отдельный проект с чётким версионированием и Changelog. Решение о создании библиотеки — инфраструктурная инвестиция: она оправдана, если у вас несколько фронтенд-приложений, несколько команд или частая проблема «в каждом проекте Button выглядит по-разному».
Как мы строим архитектуру библиотеки
Monorepo vs отдельный репозиторий Monorepo (Turborepo, Nx) — для параллельного развития библиотеки и приложений одной командой. Изменения видны сразу, без публикации пакета. Отдельный репозиторий с публикацией в npm (GitHub Packages, Verdaccio) — для нескольких независимых команд. Потребляющий проект сам выбирает версию обновления.
Структура пакета:
packages/ui/
├── src/
│ ├── components/
│ │ ├── Button/
│ │ │ ├── Button.tsx
│ │ │ ├── Button.stories.tsx
│ │ │ ├── Button.test.tsx
│ │ │ └── index.ts
│ │ └── ...
│ ├── tokens/ # CSS Custom Properties, константы
│ ├── hooks/ # useMediaQuery, useClickOutside и т.д.
│ └── index.ts # публичный API
├── package.json
└── tsconfig.json
Публичный API — критически важно: всё, что в index.ts, становится обязательством поддерживать обратную совместимость.
Сборка и бандлинг: что выбираем?
Для библиотек используем не Vite (он для приложений), а специализированные сборщики:
- tsup — самый простой. Одна команда, ESM + CJS, TypeScript из коробки. Наш основной выбор для MVP. tsup собирает компоненты в 2 раза быстрее Rollup, что ускоряет итерации.
- Rollup — когда нужен тонкий контроль tree-shaking по компонентам или множественные entry points. Настройка сложнее, но гибкость выше.
-
Vite Library Mode — если экосистема уже на Vite. Конфиг
build.libс форматамиesиcjs.
CSS не бандлим в JS. Если используем Tailwind — потребляющий проект сам запускает Tailwind с путями до наших компонентов в content. CSS-in-JS (styled-components, Emotion) поставляется с JS. Если CSS Modules — нужна отдельная сборка CSS.
Таблица сравнения сборщиков:
| Критерий | tsup | Rollup | Vite Library Mode |
|---|---|---|---|
| Скорость сборки | высокая | средняя | высокая |
| Tree-shaking per component | по умолчанию | настраиваемый | настраиваемый |
| ESM + CJS | да | да | да |
| TypeScript из коробки | да | через плагин | через плагин |
| Подходит для MVP | отлично | избыточно | если экосистема на Vite |
Система дизайн-токенов
Консистентность стилей строится на дизайн-токенах — это CSS Custom Properties, генерируемые из Figma:
/* tokens.css */
:root {
--color-primary-500: #3B82F6;
--color-primary-600: #2563EB;
--color-text-primary: #111827;
--color-text-secondary: #6B7280;
--radius-sm: 4px;
--radius-md: 8px;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--spacing-1: 4px;
--spacing-2: 8px;
--spacing-4: 16px;
}
Токены автоматически экспортируются из Figma через плагин Tokens Studio или CLI Style Dictionary. Последний принимает JSON и генерирует CSS, JS-константы, iOS Swift, Android XML — универсально.
Какие проблемы решает библиотека компонентов?
Фрагментация стилей — каждое приложение рисует Button по-своему. Библиотека задаёт единый визуал. Дублирование кода — один и тот же компонент копируется между проектами. Централизованная библиотека устраняет копипасту. Раздувание bundle — когда каждый проект тащит свою копию компонента. Оптимизация через tree-shaking уменьшает размер на 30–50%. Дополнительно, единая библиотека снижает количество багов на 20% и сокращает время онбординга новых разработчиков на 30%.
Как проектировать API компонентов?
Хороший API — предсказуемый и минимальный. Принципы:
Controlled vs Uncontrolled. Input может быть controlled (value + onChange) и uncontrolled (defaultValue). Поддерживаем оба режима.
Polymorphic компоненты. Button должен рендерить <button> по умолчанию, а с as="a" — <a>. Реализуем через generic:
type ButtonProps<T extends React.ElementType = 'button'> = {
as?: T;
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
} & React.ComponentPropsWithoutRef<T>;
Composition через slot-паттерн. Вместо leftIcon и rightIcon — <Button.Icon position="left"><SearchIcon /></Button.Icon>. Гибче, но сложнее API — выбираем под задачу.
Для сложных компонентов (Select, Dialog, Tooltip) используем Radix UI Primitives — они отвечают за accessibility, keyboard navigation, ARIA-атрибуты. Остаётся только стилизация. shadcn/ui — пример обёртки Radix в Tailwind. Согласно документации Radix UI, все примитивы проходят axe-core тесты.
Тестирование: три уровня
Unit тесты — Vitest + Testing Library (логика, состояния, accessibility):
test('Button renders disabled state', () => {
render(<Button disabled>Click</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
Visual regression — Playwright скриншоты или Chromatic (коммерческий, интеграция со Storybook). Каждый PR проверяет визуальное состояние. Visual regression тесты сокращают время ревью на 40%.
Accessibility — axe-core через jest-axe или Storybook addon a11y. Автоматически ловит ARIA-ошибки.
Версионирование и Breaking Changes
Используем semver (MAJOR.MINOR.PATCH):
- PATCH: bugfix без изменения API
- MINOR: новый компонент или опциональный prop
- MAJOR: удаление компонента, переименование prop, изменение поведения
Автоматизация — Changesets (Atlassian). Разработчик добавляет .changeset/*.md, CI сам обновляет версию и публикует в npm.
Что входит в нашу работу
- Проектирование архитектуры и выбор toolchain
- Сборка, настройка CI, версионирование
- Разработка компонентов (от базовых до сложных)
- Система дизайн-токенов и темизация
- Storybook, unit/visual/a11y тесты
- Документация, changelog, migration guides
- Публикация в npm/GitHub Packages
Типичные ошибки при создании библиотеки:
- Слишком широкий публичный API с первого релиза — лучше начать с 15–20 компонентов.
- Игнорирование accessibility — потом дорого переделывать.
- Отсутствие дизайн-токенов — стили быстро расходятся.
Как подключить библиотеку в проект?
Установка стандартная: npm install @company/ui. После этого в tailwind.config.js добавляем пути к компонентам библиотеки, если используем Tailwind. Для CSS-токенов импортируем tokens.css в корне приложения. Все компоненты импортируются из @company/ui.
Почему дизайн-токены — основа консистентности?
Без токенов дизайн быстро расходится: один разработчик использует #3B82F6, другой — #3B81F6. Токены фиксируют цвета, отступы, тени в едином месте. Изменение токена автоматически обновляет все компоненты. Это снижает количество визуальных багов на 30% и ускоряет внедрение новых тем (light/dark).
Мы гарантируем прозрачность этапов и сроков. Ориентируйтесь на цифры:
| Этап | Время |
|---|---|
| Проектирование архитектуры, выбор toolchain | 3–5 дней |
| Настройка сборки, CI, versioning | 2–3 дня |
| Базовые компоненты (Button, Input, Checkbox, Select, Modal) | 10–15 дней |
| Сложные компоненты (DataTable, DatePicker, RichTextEditor) | 10–20 дней |
| Токены, темизация (light/dark) | 3–5 дней |
| Storybook + тесты | 5–8 дней |
| Документация и первый публичный релиз | 3–5 дней |
Минимальная MVP-библиотека с 15–20 компонентами, Storybook и CI — 6–10 недель. Полноценная корпоративная библиотека на 40+ компонентов — от 4 до 6 месяцев итеративной разработки.
Хотите оценить ваш проект? Свяжитесь с нами — подберём оптимальный формат и расскажем, как быстро можно получить первую версию. Наши инженеры имеют 5+ лет опыта в создании дизайн-систем и компонентных библиотек. Закажите консультацию — обсудим технические детали и сроки.







