Config-файл может иметь любое имя и расширение `.ts`, `.js` или `.json`. CLI не ищет конфиг по соглашению: файл нужно передать явно. В руководствах используется рекомендуемое имя `svg-sprite.config.json`.
Если передан каталог, все настройки берутся из CLI. Если передан config-файл, CLI-параметры перекрывают значения файла. Общий порядок: `defaults → config → CLI`.
`--help` и `-h` выводят справку без обязательного пути. Для генерации доступны `--mode`, `--name`, `--description`, повторяемый `--input <path-or-glob>`, а также пары `--remove-size`/`--no-remove-size`, `--replace-colors`/`--no-replace-colors`, `--add-transition`/`--no-add-transition` и `--generated-notice`/`--no-generated-notice`. Переданные transform-флаги перекрывают отдельные поля, а хотя бы один `--input` полностью заменяет значение `input` из config.
Mode должен соответствовать способу публикации приложения. Bare `standalone` оставляет публичный URL приложению; Vite и Webpack modes генерируют bundler-specific подключение SVG asset.
## Единая конфигурация
Каждый config-файл описывает один независимый спрайт.
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'next@app/turbopack',
name: 'app',
description: 'Общие иконки приложения',
input: [
'./local-icons',
'../../assets/icons/*.svg',
'!../../assets/icons/deprecated-*.svg',
],
transform: {
removeSize: true,
replaceColors: true,
addTransition: true,
},
generatedNotice: true,
})
```
| Опция | Тип | По умолчанию | Назначение |
|---|---|---|---|
| `mode` | `SpriteMode` | Нет | Режим генерации; можно передать через CLI/API |
Если `name` не задано, генератор преобразует имя каталога в kebab-case. Для каталога с именем `svg-sprite` или `svg-sprites` используется имя родительского каталога.
`SpriteConfig.input` является необязательным и имеет тип `string | string[]`. Если поле отсутствует, источником служит папка `./icons` относительно папки конфига. В config-less режиме относительные пути считаются от каталога, переданного CLI или API.
Каждая строка без префикса `!` может быть путём к конкретной папке, конкретному файлу `.svg` или glob-паттерном. Папка включает только непосредственные дочерние `*.svg`. Для рекурсивного обхода вложенных каталогов укажите явный паттерн, например `icons/**/*.svg`.
Массив объединяет все включающие источники. Паттерн с префиксом `!` глобально исключает совпадения из общего результата независимо от того, какой источник их добавил.
Поддерживается следующий glob-синтаксис:
| Синтаксис | Значение |
|---|---|
| `*` | Любые символы внутри одного сегмента пути |
| `**` | Любое число вложенных каталогов |
| `?` | Один символ внутри сегмента пути |
| `{a,b}` | Одна из альтернатив |
| `[abc]` | Один символ из набора или диапазона |
| `!pattern` | Исключение совпадений из всего объединённого input |
Каждый включающий источник или паттерн должен найти хотя бы один SVG, иначе генерация завершается ошибкой. Повторяющиеся пути удаляются, а итоговый список файлов детерминированно сортируется. Разные SVG с одинаковым basename по-прежнему считаются конфликтом, потому что basename задаёт публичное имя иконки.
## Generated-модуль
После генерации React- или Next.js-каталог спрайта выглядит так:
`.svg-sprite` полностью управляется генератором и при каждой генерации заменяется целиком. Любые добавленные в него файлы будут удалены. Пользовательские файлы размещайте рядом, например в корневом `index.ts`:
Значения атрибутов в обычной HTML-разметке TypeScript не проверяет. Поэтому
неизвестный `icon="unknown"` дополнительно проверяется в runtime: компонент
скрывает внутренний SVG и сообщает об ошибке, не создавая fragment
`#undefined`. Повторный вызов `defineAppIconElement()` безопасен для того же
спрайта; конфликт с другим элементом под tag `<app-icon>` завершается ошибкой.
## React-компонент и TypeScript
Спрайт с`name: 'app'` экспортирует:
```ts
export { AppIcon, appIconNames }
export type { AppIconName, AppIconProps, AppIconStyle }
```
### Имена иконок
Имена SVG-файлов становятся допустимыми значениями `icon`:
```tsx
<AppIconicon="search"/>
<AppIconicon="unknown"/> // ошибка TypeScript
```
Runtime-список содержит те же значения:
```ts
import { appIconNames } from '@/ui/app-icons'
// readonly ['search', 'settings', 'user']
```
Имена с пробелами и другими небезопасными для SVG ID символами остаются частью публичного API. Для внутреннего fragment ID генератор создаёт стабильный безопасный hash:
Каждый каталог с конфигом создаёт независимый mode-specific контракт. React и Next.js создают React-компонент и типы, `standalone@vite` и `standalone@webpack` — Web Component и типы, а bare `standalone` — SVG и JSON manifest:
SVG внутри `<img>` изолирован от CSS страницы. `color` и `--icon-color-N` на внешнем элементе не изменяют его внутренние цвета.
### Через CSS
```css
.icon {
background: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
}
```
Для одноцветного силуэта можно использовать mask:
```css
.icon {
background-color: currentColor;
mask: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
}
```
Mask не сохраняет исходные цвета, gradients и различия между `fill` и `stroke`.
Путь в CSS разрешается относительно самого CSS-файла. В примерах CSS-файл находится рядом с`svg-sprite.config.ts`.
## Assets и кеширование
Generated component или standalone facade передаёт SVG сборщику как отдельный asset:
- Vite использует статический импорт с`?no-inline`;
- Webpack 5, Turbopack и Next.js используют `new URL(..., import.meta.url)`;
- SVG path-данные не сериализуются в generated JavaScript.
Bare `standalone` не участвует в asset pipeline: приложение само копирует или
публикует `sprite.svg` и отвечает за URL, версионирование и cache policy.
При стандартном именовании assets сборщик добавляет content hash:
```text
/assets/sprite-<hash>.svg
```
Это позволяет кешировать SVG отдельно от JavaScript. Изменение React-кода не меняет содержимое спрайта, а изменение иконок создаёт новую версию asset.
HTTP cache headers, CDN и `Cache-Control` настраиваются приложением или платформой размещения. Для Webpack имя итогового файла зависит от `assetModuleFilename` проекта.
## Трансформации SVG
Все трансформации включены по умолчанию и настраиваются независимо:
| `replaceColors` | Заменяет найденные `fill` и `stroke` на `--icon-color-N` |
| `addTransition` | Добавляет transitions для `fill` и `stroke` в цветные элементы и generated styles |
Чтобы отключить отдельную операцию:
```ts
export default defineSpriteConfig({
mode: 'next@app/turbopack',
transform: {
removeSize: false,
replaceColors: false,
addTransition: false,
},
})
```
Исходные SVG не изменяются. Трансформации применяются только к содержимому generated-спрайта.
## Управление цветами
### Монохромные иконки
Если найден один цвет, fallback становится `currentColor`:
```svg
stroke="var(--icon-color-1, currentColor)"
```
Цвет задаётся через prop или CSS:
```tsx
<AppIconicon="search"color="rebeccapurple"/>
```
### Многоцветные иконки
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
```svg
fill="var(--icon-color-1, #798198)"
fill="var(--icon-color-2, #ffffff)"
fill="var(--icon-color-3, #129d9d)"
```
Можно заменить только необходимые значения:
```css
.icon {
--icon-color-1: #4b5563;
--icon-color-3: #14b8a6;
}
```
### Ограничения
-`none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
- надёжнее всего обрабатываются цвета в атрибутах `fill`, `stroke` и inline `style`;
- CSS-классы и внешние stylesheets внутри SVG не являются основным сценарием трансформации;
- значения `url(#...)` могут быть заменены вместе с цветами, поэтому gradients и patterns требуют отдельного спрайта с`replaceColors: false`;
- masks, filters и сложные внутренние CSS-правила требуют визуальной проверки;
- CSS-переменные страницы доступны через `<svg><use>`, но не внутри `<img>` и CSS background.
Для сложной иконки можно отключить `replaceColors` в конфигурации отдельного спрайта.
## SpriteViewer
Viewer использует один Web Component с Shadow DOM для всех modes. React и будущие framework-компоненты являются bridge к этому же элементу, поэтому визуал и поведение не дублируются.
Bare `standalone` подключает самостоятельный browser bundle и передаёт URL JSON manifest и опубликованного SVG:
Viewer показывает группы, поиск, `viewBox`, CSS-переменные и fallback-цвета. React/Next manifests получают вкладки React, SVG, IMG и CSS; standalone manifests получают SVG, IMG и CSS. Цветовые значения можно менять в интерфейсе и сразу проверять результат.
### Тема Viewer
По умолчанию `colorTheme="auto"` следует `prefers-color-scheme`. Можно передать `light` или `dark` явно:
```tsx
<SpriteViewersources={sources}colorTheme="dark"/>
```
Для синхронизации с темой приложения:
```tsx
<SpriteViewer
sources={sources}
colorTheme={appTheme}
onColorThemeChange={setAppTheme}
/>
```
`@gromlab/svg-sprites/react` содержит `'use client'` и рендерит Web Component host; внутренний Shadow DOM создаётся после загрузки browser runtime. В Next.js App Router размещайте Viewer внутри отдельной Client Component boundary и используйте только на debug-маршруте или во внутреннем инструменте.
## Generated-файлы, Git и CI
Все modes, кроме bare `standalone`, создают локальный `.gitignore` для:
```text
/.svg-sprite/
```
Локальный `.gitignore` следует один раз добавить в репозиторий. Он исключает остальные generated-файлы, поэтому генерацию нужно запускать перед командами, которые импортируют sprite-модуль:
CI должен выполнять generation script до сборки или проверки типов. Локальная установка package не нужна, если CI не использует Viewer, package-типы config или программный API.
Bare `standalone` не создаёт `.gitignore` и сохраняет пользовательский файл. Если после другого mode остался управляемый `.gitignore`, bare mode удалит его. В остальных modes генератор откажется перезаписать пользовательский `.gitignore` без generated marker. Корневой `index.ts` остаётся пользовательским и может переэкспортировать generated API.
- Viewer не видит спрайт: для bundler modes проверьте путь к `.svg-sprite/svg-sprite.manifest.js`; для bare `standalone` — URL опубликованных `svg-sprite.manifest.json` и `sprite.svg`. Выполните генерацию до запуска приложения.