# Производительность

> Гранулярность — главное обещание продукта. Страница показывает, чем оно измеряется и как проверить его самому.

- Page: https://granularity.tech/ru/docs/performance
- Last reviewed: 2026-10-27

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

## Две стороны, и они не коррелируют

Вес компонента складывается из кода и стилей, и эти величины живут отдельно:

| Компонент | CSS, прирост листа | JS, сам компонент |
|---|---:|---:|
| `GrCard` | 764 B | 3 483 B |
| `GrDialog` | 1 111 B | 11 779 B |
| `GrDataTable` | 4 398 B | 37 790 B |
| `GrSelect` | 4 311 B | 24 283 B |

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

## Код: подпуть вместо бареля

```ts
// один компонент и его граф
import { GrButton } from '@feugene/granularity/components/GrButton'

// весь пакет — granum отвергает такой импорт: ComponentRootImportError
import { GrButton } from '@feugene/granularity'
```

Верхняя строка — это и есть гранулярность. Вес подпути — gzip всего, что он
тянет из `dist`, вместе с вложенными компонентами, но без внешних пакетов и без
CSS. Самый лёгкий подпуть — `GrSkeleton`, 1.7 kB: заглушке загрузки не нужен
ни один соседний компонент. Самый тяжёлый — `GrDataTable`, 121.6 kB. Весь пакет
из корня — 646.5 kB.

:::callout{type="warning"}
**Складывать веса подпутей нельзя.** Общий чанк посчитан в каждой строке заново,
а платится один раз: сумма пяти самых тяжёлых строк даёт 504.3 kB, а вместе они
весят 251.8 kB. Набор считается объединением, а не суммой — и это верхняя
граница: бандлер приложения трясёт дерево дальше и минифицирует повторно.
:::

Полная таблица по каждому подпути генерируется из собранного `dist` на каждом
релизе — она лежит в пакете и на странице каждого компонента в
[каталоге](/ru/components).

## Стили: платите за выбранное

CSS не импортируется файлами — его собирает granum ровно для тех компонентов,
которые вы перечислили в `components`, и для их зависимостей. Что нужно каждому
компоненту — классы, собственный `styles.css`, токены, — записано в манифесте
пакета, и лист собирается по манифестам, а не по `node_modules`. Структура
расхода такая:

:::steps
1. **Первый компонент несёт фундамент** — токены, базовый слой, preflight, тему с режимом по умолчанию. Это разовая плата.
2. **Каждый следующий добавляет свои сотни байт** — от семи сотен у карточки до четырёх килобайт у селекта.
3. **Второй режим стоит меньше килобайта**, а не вдвое: режимы отличаются значениями ролей, а не правилами.
:::

Не перечислять `components` вовсе — рабочий вариант: тогда в лист приедут все
компоненты провайдера. Разница между «всё» и «один» на общем листе — меньше чем
вчетверо, а не в сто раз, потому что фундамент один на всех. Гранулярность стилей
имеет смысл, но её эффект скромнее, чем у кода, и честно сказать об этом дешевле,
чем потом объясняться.

## Рантайм

- **Под ядром — только свой пакет токенов.** Это единственная зависимость
  ядра, у неё самой зависимостей нет, и её кода ядро в рантайме не импортирует:
  из неё берёт значения сборка. Единственная обязательная внешняя библиотека —
  `@floating-ui/dom`, и она объявлена peer-зависимостью приложения, чтобы не
  приехать второй копией.
- **CSS компонента приходит через манифест, а не через чанк.** JS-чанки пакета
  стилей не импортируют: granum берёт `styles.css` компонента из манифеста и
  кладёт его в слой `granum.components` — только для выбранных компонентов.
  Отдельного стилевого импорта нет, и это не удобство, а условие: иначе
  гранулярность ломалась бы на первом же забытом импорте.
- **Реестр покомпонентных токенов и тест-помощники — отдельные подпути**
  (`/tokens`, `/testing`), и барель ядра их не импортирует. Подсветки кода в ядре нет
  вовсе: она живёт в `@feugene/granularity-code/highlight`.

## Как померить у себя

:::steps
1. Соберите приложение с одним компонентом и снимите gzip эмитированного CSS и JS.
2. Добавьте второй компонент и снимите снова. Разница — его настоящая цена в вашем проекте.
3. Сравните с барелем: импорт из корня granum не пропустит, поэтому на время замера выключите guard (`js: { guard: 'off' }`) и повторите. Разница — то, от чего бережёт подпуть.
:::

Числа на этом сайте снимают скрипты, а не сборка приложения. В таблице в начале
страницы лист собирает granum по манифесту ядра без исходников приложения, а
код — esbuild по подпути компонента, где `vue`, `@floating-ui/dom` и
`@feugene/fint-i18n` вынесены наружу. Поэтому смотреть на них стоит как на
порядок величины: ваш результат зависит от версии бандлера, настроек
минификации и от того, что ещё лежит в графе.

## Что не ускорит ничего

- **`importStyle: true` у резолвера авто-импорта.** Ядру он не нужен: стили
  компонентов granum уже взял из манифестов, а подпутей
  `components/<Name>/styles.css` ядро не публикует — включённая опция сломала
  бы сборку.
- **Ручные импорты `styles/*.css` и `themes/*.css`** поверх листа granum. Они
  добавят вес, а не уберут: токены, базу и режимы темы granum уже положил в свои слои, а файл,
  импортированный вне слоёв, ещё и перебьёт их в каскаде.
- **Сужение `modes` темы до одного режима** ради экономии. Второй режим стоит
  меньше килобайта — это не то место, где стоит терять переключение.
