Установка

Что ставится, почему именно это и куда — dependencies или devDependencies. Плюс иконки и опциональные интеграции.

Быстрый старт даёт один рабочий путь без объяснений. Эта страница объясняет: почему состав зависимостей именно такой, что из него попадает в бандл, а что живёт только на сборке.

Требования

ЧтоВерсияПочему жёстко
Node≥ 22Объявлено в engines, пакет ESM-only
"type": "module"обязательноCommonJS-сборки нет и не планируется
Vue^3.5peer-зависимость
@floating-ui/dom^1.8обязательная runtime peer-зависимость
UnoCSS≥ 66вместе с @unocss/preset-mini или @unocss/preset-wind4

@feugene/fint-i18n — peer тоже, но помеченный необязательным: без него компоненты говорят по-английски встроенными строками, а не падают. Подробности — на странице локализации.

Единственный поддерживаемый способ

Подключение идёт через UnoCSS-пресет presetGranularNode и granular-провайдер пакета. Прямые импорты CSS-файлов, импорт «всего сразу» из корня и подключение styles.css в обход пресета не поддерживаются — они работают ровно до первого обновления и ломаются молча.

Исключение одно и названо в самом пакете: @feugene/granularity/styles.css — готовый лист с токенами, базовым слоем, preflight и обеими темами для тех, кто пресет не запускает вовсе. Он даёт рабочую основу, но не даёт утилитарных классов, которыми нарисованы шаблоны компонентов.

Что и куда

bash
# в dependencies — попадает в приложение
yarn add vue @feugene/granularity @floating-ui/dom @unocss/reset

# в devDependencies — исполняется только на сборке
yarn add -D unocss @feugene/unocss-preset-granular @unocss/preset-mini

@feugene/granularity — в dependencies: его компоненты импортируются из исходников приложения и попадают в бандл.

@floating-ui/dom — в dependencies приложения, а не внутрь пакета. На нём построено позиционирование GrDropdown, GrSelect, GrAutocomplete, GrTreeSelect, GrTooltip и GrPopover. Пакет держит библиотеку внешней и не бандлит внутрь dist — иначе приложение, которое само использует floating-ui, получило бы вторую копию.

Пресет, unocss и preset-mini — в devDependencies: они исполняются в uno.config.ts и ни одной строкой не попадают в бандл. granularityProvider реэкспортируется самим пакетом и своих зависимостей не требует.

Модальный слой — GrModal, GrDialog, GrDrawer, GrImageViewer, GrCommandPalette — не требует внешних зависимостей вовсе. Ловушка фокуса, inert для фона, порядок Esc и возврат фокуса — собственные примитивы пакета. @headlessui/vue был убран в 0.15.0 и peer-зависимостью не является: если он остался в проекте ради этого пакета, его можно снести.

Наращивание конфига

Минимальный рабочий конфиг — провайдер и больше ничего:

uno.config.ts
import { defineConfig, presetMini } from 'unocss'
import { presetGranularNode } from '@feugene/unocss-preset-granular/node'
import granularityProvider from '@feugene/granularity/granular-provider/node'

export default defineConfig({
  presets: [presetMini(), presetGranularNode({ providers: [granularityProvider] })],
})

Он уже подмешивает tokens.css и base.css, включает все компоненты провайдера с их preflight и поднимает rules, variants и safelist. Дальше опциями сужают и уточняют:

ОпцияЧто делает
componentsСписок компонентов вместо «всех». Единственное место, где вы платите за гранулярность вниманием
themes.namesКакие темы попадут в лист. По умолчанию — все темы провайдера
themeFiles, tokensFile, baseFileПодмена CSS темы, токенов или базового слоя файлами приложения
layerКладёт preflight пакета в отдельный слой и даёт ему свой виртуальный модуль

granularContent(options) в content верхнего уровня — обязателен, когда компоненты приезжают подпутями из собранного dist: extractor UnoCSS иначе туда не заглянет. Читается он только из верхнего уровня конфига, не из пресета.

Иконки

Свои иконки пакет привозит с собой. Стрелка селекта, крестик очистки, галочка выбранной опции, спиннер, ручка переноса компилируются в dist при сборке пакета. Ставить unplugin-icons или коллекцию ради них не нужно.

Своя иконка приходит двумя способами. Пропы icon принимают либо Vue-компонент, либо класс:

vue
<script setup lang="ts">
import IconUser from '~icons/lucide/user'
</script>

<template>
  <!-- Компонент: работает всегда, настраивать нечего. -->
  <GrTabs :tabs="[{ value: 'a', label: 'Profile', icon: IconUser }]" />

  <!-- Класс: CSS для него генерирует ваш конфиг, а не пакет. -->
  <GrTabs :tabs="[{ value: 'a', label: 'Profile', icon: 'i-lucide-user' }]" />
</template>

i-lucide-* — утилита UnoCSS, и делает её ваша сборка. Без presetIcons и коллекции иконок класс останется классом: место под иконку будет, картинки не будет, и сборка при этом пройдёт молча.

bash
yarn add -D @unocss/preset-icons @iconify-json/lucide

Опциональные интеграции

  • @feugene/unplugin-granularity — резолвер для unplugin-vue-components: авто-импорт компонентов и директив в шаблонах. Вставляет статические импорты в SFC, поэтому tree-shaking остаётся идеальным.
  • createGranularity из @feugene/granularity/vue — runtime-адаптер для директив в render/JSX, общего provide и globalProperties. Сам он не импортирует ни одного компонента: что передадите, то и зарегистрируется.

Оба дополняют основной способ установки, а не заменяют его. Настройка обоих — в конфигурации.

Последняя ревизия: 2026-09-01