Что на самом деле попадает в бандл при импорте одного компонента
Разбор веса одной дизайн-системы — во что обходится компонент, во что вторая тема и почему CSS и JS не коррелируют.
«Это же просто кнопка» — так умирают бюджеты бандла. Честный вопрос не в том, сколько весит компонент, а в том, что приезжает вместе с ним: обвязка фреймворка, стили всего, что листу велели сгенерировать, вторая тема, которую никто не просил. Ниже — ответ для одной дизайн-системы, снятый замером, а не заявленный.
Все числа сняты 2026-08-29 на ядре 0.38.0 и пресете 0.15.0. Метод назван рядом с каждым: число без метода — это утверждение, а не измерение.
Две цены, и они не связаны
Компонент стоит дважды: в CSS и в JavaScript. Кажется, что тяжёлый компонент тяжёл в обоих. Это не так.
| Компонент | Сколько добавляет к листу | Собственный код |
|---|---|---|
GrCard | 223 B | 1 870 B |
GrDialog | 318 B | 9 789 B |
GrDataTable | 705 B | 16 243 B |
GrSelect | 2 335 B | 19 819 B |
Сжато gzip, фреймворк объявлен внешним. У GrDialog кода в тридцать раз больше,
чем стилей, у GrSelect — в восемь. Причина скучная и её стоит знать: стили
растут от числа видимых состояний, код — от количества поведения. Диалог
это коробка с ловушкой фокуса. Селект — коробка со списком, фильтрацией,
клавиатурной навигацией и плавающей панелью.
Практическое следствие: вес компонента нельзя оценить, посмотрев на него. Самый лёгкий в пакете весит 1 455 B, самый тяжёлый — 19 819 B, разброс в 13.6 раза, и внешняя разница между ними не отличается в 13.6 раза ничем.
Во что обходится первый компонент
Здесь «это же просто кнопка» действительно неверно — и здесь же действительно верно.
| Лист | Сжатый |
|---|---|
| Один компонент, одна тема | 7 504 B |
| Один компонент, две темы | 8 250 B |
| Все компоненты ядра, две темы | 17 430 B |
Первый компонент стоит 7 504 B, а оставшиеся 76 — 9 180 B на всех. Это не парадокс: первый оплачивает фундамент — объявления токенов, базовый слой, preflight, — а каждый следующий платит только за свои утилиты.
То есть «просто кнопка» неверно про первую кнопку и примерно верно про вторую. Добавляя дизайн-систему ради одного компонента, вы платите за дизайн-систему. Добавляя десятый, вы платите за компонент.
Вторая тема стоит 746 байт
Не 746 килобайт и не второй лист: 746 B, потому что тема — это блок значений
кастомных свойств под селектором, а не копия стилей. Каждое правило с
var(--gr-bg) эмитится один раз, сколько бы тем его ни определяло.
Здесь ошибаются в обе стороны. Отказываются от тёмной темы ради веса, которого она не стоила, и заводят шесть брендовых тем, считая их бесплатными: в CSS они бесплатны, а в вычитке, проверке контраста и решениях дизайна — нет. Байты здесь наименьшая из статей расхода.
Где гранулярные импорты действительно помогают
Пакет объявляет 136 путей экспорта, в ядре 77 компонентов. Импорт подпутём, а не из корневого бареля, — это то, что оставляет остальные 76 снаружи:
// Отсюда достижим весь барель — tree-shaking обязан доказать,
// что остальное не используется, а через реэкспорты это удаётся не всегда.
import { GrButton } from '@feugene/granularity'
// Один компонент и его граф. Доказывать нечего.
import { GrButton } from '@feugene/granularity/components/GrButton'Работают обе строки. Вторая меньше в любом сборщике и такая же в лучшем — в этом и весь довод: выигрыш не в том, что она быстрее, когда всё сложилось, а в том, что она не зависит от того, сложилось ли.
Сторона CSS не встряхивается вовсе — она порождается. В листе лежит то, что
конфигу велели сгенерировать, и поэтому сужение components в uno.config.ts —
единственное место, где за гранулярность платят вниманием:
const granular = {
providers: [granularityProvider],
components: [{ provider: '@feugene/granularity', names: ['GrButton', 'GrCard'] }],
themes: { names: ['light', 'dark'] },
}Не написать components — получить все: 17 430 B вместо 8 473 B. Это настоящая
разница и плохая настройка, чтобы унаследовать её случайно.
Чего эти числа не говорят
Три честных ограничения.
Это сжатые байты, а не время разбора. 19 819 B GrSelect исполняются дольше,
чем 19 819 B разметки, и ни одно из чисел не говорит о третьей отрисовке.
Фреймворк во всех замерах JS внешний. Vue в этих числах нет, потому что его нет в них и у вас — он у вас уже есть. Если нет, прибавьте: тогда дизайн-система перестанет быть интересной частью бюджета.
Ноль runtime-зависимостей — свойство ядра, а не семейства. Ядро объявляет 0 runtime-зависимостей; спутники, оборачивающие чужой редактор или подсветку, объявляют свои, и они перечислены на странице каждого пакета.
Одно число, которое стоит запомнить
Не 7 504 и не 13.6 раза. Вот это: первый компонент дизайн-системы стоит примерно столько же, сколько все остальные вместе. Бюджетируйте решение, а не импорт.