Быстрый старт
Пять шагов от пустой директории до цветной кнопки на экране. Всё, что глубже, — на соседних страницах.
Самая короткая полезная страница сайта. Здесь нет вариантов, оговорок и «а если у вас Nuxt» — один путь, который доводит до работающего компонента. Разветвления начинаются на установке и в конфигурации.
Что понадобится
- Node 22 или новее. Так объявлено в
enginesпакета: Yarn 1 на старой Node откажется его ставить, npm и pnpm только предупредят. Сам пакет ESM-only —"type": "module"и ни одного условияrequireвexports. - Приложение на ES-модулях. CommonJS-сборки у пакета нет, подключается он через
import, как это делает Vite."type": "module"вpackage.jsonприложения рекомендуется, но не проверяется: конфиг granum здесь и так.mjs. - Vue 3.5 или новее и сборка на Vite 8 — под него объявлен peer
@feugene/granum. Другие сборщики не запрещены, но и не проверяются.
Установка
npm i @feugene/granularity vue @floating-ui/dom @unocss/resetpnpm add @feugene/granularity vue @floating-ui/dom @unocss/resetyarn add @feugene/granularity vue @floating-ui/dom @unocss/resetbun add @feugene/granularity vue @floating-ui/dom @unocss/resetИ то, что работает только на сборке и в бандл не попадает:
npm i -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tscpnpm add -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tscyarn add -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tscbun add -d vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc@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 не
ходит: файлы пакета он открывает, только когда манифесту нельзя доверять, и
только те, что в манифесте перечислены. Точка правды одна:
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 приедут все компоненты
провайдера. Перечисление сужает лист до нужного набора, и это единственное
место, где вы платите за гранулярность вниманием.
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 одним и тем же объектом: разошлись — компоненты
приезжали без стилей, и сборка об этом молчала. Такой развилки больше нет.
Два импорта, и порядок между ними несущий
import './reset.css'
import 'virtual:granum.css'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')@import '@unocss/reset/tailwind-compat.css' layer(reset);Сброс уезжает в свой слой, и это не оформление. granum отдаёт всё своё в слои
granum.*, а нелейерный CSS бьёт ЛЮБОЙ @layer независимо от специфичности:
вне слоя button { color: inherit } из сброса перебил бы утилиты компонента, и
кнопка приехала бы с цветом текста страницы.
Слой обязан объявиться раньше слоёв granum — место слоя в каскаде задаёт его
первое появление, — поэтому reset.css импортируется первым. Перепутанный
порядок не даёт ни ошибки, ни предупреждения.
Виртуальный модуль CSS теперь один — virtual:granum.css. Токены, базовый
слой, темы, стили компонентов и утилиты, которыми нарисованы их шаблоны,
приезжают одним листом: забыть половину фундамента и получить цвета без вёрстки
больше нельзя.
Первый компонент
<script setup lang="ts">
import { GrButton } from '@feugene/granularity/components/GrButton'
</script>
<template>
<GrButton tone="primary">Save</GrButton>
</template>Импорт из подпути, а не из корня пакета, — это и есть гранулярность. Он тянет
один компонент и его граф, а не барель. Компонент из корня granum отвергает
ошибкой сборки ComponentRootImportError.
Запускайте vite. Кнопка должна быть цветной, со скруглёнными углами и с
фокусным кольцом по Tab. Если она серая и голая — лист не импортирован вовсе.
Если фон на месте, а текст цвета страницы и отступов нет — сброс импортирован
после листа. Оба случая разобраны на странице
типовых поломок.
Дальше
- Установка — почему состав зависимостей именно такой, иконки, опциональные интеграции.
- Конфигурация — значения по умолчанию, локаль, оверрайды на уровне приложения.
- Темизация — смена бренда без правки компонентов.
- Каталог компонентов — что вообще есть.