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

  • Устройство
  • 5 мин
  • кода: 1

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

Ревизия 2026-10-16

На этой странице

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

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

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

КомпонентCSS, прирост листаJS, сам компонент
GrCard235 B2 779 B
GrDialog670 B9 989 B
GrDataTable2 911 B36 431 B
GrSelect3 037 B23 216 B

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

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

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

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

Верхняя строка — это и есть гранулярность. Вес подпути — gzip всего, что он тянет из dist, вместе с вложенными компонентами, но без внешних пакетов и без CSS. Самый лёгкий подпуть — обёртка GrButtonGroup: сама по себе она весит 1.5 kB, но без своих кнопок не используется — GrButton приходит в неё слотом и импортируется своим подпутём. Самый тяжёлый — GrDataTable, 115.8 kB. Весь пакет из корня — 655.4 kB.

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

Полная таблица по каждому подпути генерируется из собранного dist на каждом релизе — она лежит в пакете и на странице каждого компонента в каталоге.

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

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

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

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

Рантайм

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

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

  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 поверх листа granum. Они добавят вес, а не уберут: токены, базу и темы granum уже положил в свои слои, а файл, импортированный вне слоёв, ещё и перебьёт их в каскаде.
  • Сужение themes.names до одной темы ради экономии. Вторая тема стоит около полутора килобайт — это не то место, где стоит терять переключение.