# Быстрый старт

> Пять шагов от пустой директории до цветной кнопки на экране. Всё, что глубже, — на соседних страницах.

- Page: https://granularity.tech/ru/docs/getting-started
- Last reviewed: 2026-10-16

Самая короткая полезная страница сайта. Здесь нет вариантов, оговорок и «а если
у вас Nuxt» — один путь, который доводит до работающего компонента. Разветвления
начинаются на [установке](/ru/docs/installation) и в
[конфигурации](/ru/docs/configuration).

## Что понадобится

:::steps
1. **Node 22 или новее.** Так объявлено в `engines` пакета: Yarn 1 на старой Node откажется его ставить, npm и pnpm только предупредят. Сам пакет ESM-only — `"type": "module"` и ни одного условия `require` в `exports`.
2. **Приложение на ES-модулях.** CommonJS-сборки у пакета нет, подключается он через `import`, как это делает Vite. `"type": "module"` в `package.json` приложения рекомендуется, но не проверяется: конфиг granum здесь и так `.mjs`.
3. **Vue 3.5 или новее** и сборка на **Vite 8** — под него объявлен peer `@feugene/granum`. Другие сборщики не запрещены, но и не проверяются.
:::

## Установка

::package-manager{npm="npm i @feugene/granularity vue @floating-ui/dom @unocss/reset" pnpm="pnpm add @feugene/granularity vue @floating-ui/dom @unocss/reset" yarn="yarn add @feugene/granularity vue @floating-ui/dom @unocss/reset" bun="bun add @feugene/granularity vue @floating-ui/dom @unocss/reset"}

И то, что работает только на сборке и в бандл не попадает:

::package-manager{npm="npm i -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc" pnpm="pnpm add -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc" yarn="yarn add -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc" bun="bun add -d vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc"}

:::callout{type="warning"}
`@floating-ui/dom` — обязательная peer-зависимость, а не рекомендация. На ней
держится позиционирование всех выпадающих панелей — `GrSelect`,
`GrAutocomplete`, `GrTreeSelect`, `GrDropdown`, `GrDropdownMenu`,
`GrContextMenu`, `GrTooltip`, `GrPopover`, `GrColorPicker` — и всех, кто их
рендерит, вроде `GrPagination`, `GrDataTable` и `GrSidebar`. Без неё сборка
остановится на первом же таком импорте: Vite не найдёт `@floating-ui/dom`.
Модальный слой, наоборот, не требует ничего: ловушка фокуса, `inert` и порядок
Esc — собственные примитивы пакета.
:::

## Конфигурация

CSS дизайн-системы не импортируется файлами — его собирает granum. Состав
пакета он читает из манифеста, объявленного экспортом, и по `node_modules` не
ходит: файлы пакета он открывает, только когда манифесту нельзя доверять, и
только те, что в манифесте перечислены. Точка правды одна:

```js title="granum.config.mjs"
import { windEngine } from '@feugene/granum-engine-wind'
import { defineGranumConfig } from '@feugene/granum/vite'

export default defineGranumConfig({
  engine: windEngine(),
  providers: ['@feugene/granularity'],
  components: [{ provider: '@feugene/granularity', names: ['GrButton'] }],
  themes: { names: ['light', 'dark'] },
  appSources: { dirs: ['src'] },
})
```

`components` можно не писать вовсе — тогда в CSS приедут все компоненты
провайдера. Перечисление сужает лист до нужного набора, и это единственное
место, где вы платите за гранулярность вниманием.

```ts title="vite.config.ts"
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import { granum } from '@feugene/granum/vite'
import granumConfig from './granum.config.mjs'

export default defineConfig({ plugins: [Vue(), granum(granumConfig)] })
```

Конфиг читают в одном месте, а не в двух. У пресета v1 его приходилось отдавать
и в `content`, и в `presets` одним и тем же объектом: разошлись — компоненты
приезжали без стилей, и сборка об этом молчала. Такой развилки больше нет.

## Два импорта, и порядок между ними несущий

```ts title="src/main.ts"
import './reset.css'
import 'virtual:granum.css'

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
```

```css title="src/reset.css"
@import '@unocss/reset/tailwind-compat.css' layer(reset);
```

:::callout{type="warning"}
Сброс уезжает в свой слой, и это не оформление. granum отдаёт всё своё в слои
`granum.*`, а нелейерный CSS бьёт ЛЮБОЙ `@layer` независимо от специфичности:
вне слоя `button { color: inherit }` из сброса перебил бы утилиты компонента, и
кнопка приехала бы с цветом текста страницы.

Слой обязан объявиться раньше слоёв granum — место слоя в каскаде задаёт его
первое появление, — поэтому `reset.css` импортируется первым. Перепутанный
порядок не даёт ни ошибки, ни предупреждения.
:::

Виртуальный модуль CSS теперь один — `virtual:granum.css`. Токены, базовый
слой, темы, стили компонентов и утилиты, которыми нарисованы их шаблоны,
приезжают одним листом: забыть половину фундамента и получить цвета без вёрстки
больше нельзя.

## Первый компонент

```vue title="src/App.vue"
<script setup lang="ts">
import { GrButton } from '@feugene/granularity/components/GrButton'
</script>

<template>
  <GrButton tone="primary">Save</GrButton>
</template>
```

Импорт из подпути, а не из корня пакета, — это и есть гранулярность. Он тянет
один компонент и его граф, а не барель. Компонент из корня granum отвергает
ошибкой сборки `ComponentRootImportError`.

Запускайте `vite`. Кнопка должна быть цветной, со скруглёнными углами и с
фокусным кольцом по Tab. Если она серая и голая — лист не импортирован вовсе.
Если фон на месте, а текст цвета страницы и отступов нет — сброс импортирован
после листа. Оба случая разобраны на странице
[типовых поломок](/ru/docs/troubleshooting).

## Дальше

- [Установка](/ru/docs/installation) — почему состав зависимостей именно такой, иконки, опциональные интеграции.
- [Конфигурация](/ru/docs/configuration) — значения по умолчанию, локаль, оверрайды на уровне приложения.
- [Темизация](/ru/docs/theming) — смена бренда без правки компонентов.
- [Каталог компонентов](/ru/components) — что вообще есть.
