This commit is contained in:
2026-07-15 12:27:46 +03:00
parent ab7042001a
commit 44afec7cdb
35 changed files with 1056 additions and 1224 deletions

View File

@@ -1,6 +1,6 @@
# @gromlab/svg-sprites
[🇬🇧 English](README.md) | 🇷🇺 Русский
[🇬🇧 English](https://github.com/gromlab-ru/svg-sprites/blob/master/README.md) | 🇷🇺 Русский
![npm](https://img.shields.io/npm/v/@gromlab/svg-sprites) ![license](https://img.shields.io/npm/l/@gromlab/svg-sprites)
@@ -24,20 +24,6 @@
В приложении не приходится работать со спрайтом напрямую. Вы используете его так же, как обычную SVG-иконку, но получаете один компонент, автокомплит и TypeScript-проверку всех имён.
В `standalone@vite` и `standalone@webpack` тот же подход доступен без React:
```ts
import { defineAppIconElement } from './app-icons'
defineAppIconElement()
```
```html
<app-icon icon="search" style="font-size: 24px"></app-icon>
```
Bare `standalone` остаётся минимальным и генерирует только SVG asset и JSON manifest без JavaScript runtime.
## AI-friendly из коробки
`@gromlab/svg-sprites` сразу рассчитан на работу с AI-агентами. Подключите готовый skill и поручите агенту настройку, миграцию или диагностику без длинных инструкций и ручного изучения документации.
@@ -46,61 +32,54 @@ Bare `standalone` остаётся минимальным и генерируе
[🇬🇧 Скачать AI skill (на английском)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites.zip)
## От SVG до компонента за четыре шага
## От SVG до компонента за три шага
Основной пример использует Next.js App Router и Turbopack.
### 1. Генерируйте без установки пакета
### 1. Укажите нужные иконки
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites --help
```
`npx` временно скачивает CLI, не добавляет `@gromlab/svg-sprites` в
`package.json`, а generated production runtime не импортирует package.
### 2. Укажите нужные иконки
SVG могут оставаться в существующей структуре проекта:
Создайте папки для исходных иконок и спрайта:
```text
src/
├── assets/icons/
── search.svg
└── settings.svg
├── features/profile/
└── user.svg
└── ui/app-icons/
└── svg-sprite.config.ts
assets/
├── app-icons/
── svg-sprite.config.json
└── svg-icons/
├── search.svg
└── settings.svg
```
Создайте конфигурацию спрайта:
```ts
// src/ui/app-icons/svg-sprite.config.ts
export default {
mode: 'next@app/turbopack',
name: 'app',
input: [
'../../assets/icons/search.svg',
'../../assets/icons/settings.svg',
'../../features/profile/user.svg',
],
```json
{
"mode": "next@app/turbopack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
### 3. Добавьте генерацию
`input` поддерживает пути к папкам, отдельным SVG и glob-шаблоны.
### 2. Добавьте генерацию
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/app-icons/svg-sprite.config.ts",
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"prebuild": "npm run sprites"
}
}
```
Создайте точку входа для сгенерированного API:
```ts
// assets/app-icons/index.ts
export * from './.svg-sprite/index.js'
```
Первый запуск:
```bash
@@ -109,10 +88,11 @@ npm run sprites
Пакет создаст `AppIcon`, TypeScript-типы и отдельный SVG-спрайт.
### 4. Используйте как обычную иконку
### 3. Используйте как обычную иконку
```tsx
import { AppIcon } from '@/ui/app-icons'
// app/page.tsx
import { AppIcon } from '../assets/app-icons'
export default function SearchButton() {
return (
@@ -277,6 +257,7 @@ README знакомит с возможностями проекта и пока
### Технические материалы
- [Индекс документации](docs/ru/README.md)
- [Конфигурация](docs/ru/configuration.md)
- [Технический справочник](docs/ru/reference/technical.md)
- [Программный API](docs/ru/reference/programmatic-api.md)

View File

@@ -3,6 +3,8 @@
Для настройки выберите guide одного exact mode. Каждый guide является
самостоятельным документом и без изменений используется в AI skills.
Общий формат JSON, JavaScript и TypeScript config-файлов описан в [руководстве по конфигурации](configuration.md).
## Гайды быстрого старта
| Проект | Exact mode | Guide |
@@ -20,10 +22,11 @@
Все guides используют один порядок:
1. Генерация спрайта через `npx` без добавления package в проект.
2. Необязательное подключение Viewer для дебага и превью.
3. Необязательная типизация конфига через package или локальный copy-paste type.
2. Использование спрайта в приложении.
3. Необязательное подключение Viewer для дебага и превью.
## Справочники
- [Конфигурация](configuration.md)
- [Технический справочник](reference/technical.md)
- [Программный API](reference/programmatic-api.md)

99
docs/ru/configuration.md Normal file
View File

@@ -0,0 +1,99 @@
# Конфигурация
Каждый config-файл описывает один независимый спрайт. CLI не ищет конфиг автоматически, поэтому всегда передавайте путь явно:
```bash
npx --yes @gromlab/svg-sprites path/to/svg-sprite.config.json
```
## JSON
JSON подходит для большинства проектов и не требует локальной установки пакета:
```json
{
"mode": "next@app/turbopack",
"name": "app",
"description": "Общие иконки приложения",
"input": [
"./icons",
"../../assets/icons/**/*.svg",
"!../../assets/icons/deprecated-*.svg"
],
"transform": {
"removeSize": true,
"replaceColors": true,
"addTransition": true
},
"generatedNotice": true
}
```
| Поле | По умолчанию | Назначение |
|---|---|---|
| `mode` | Нет | Exact mode, соответствующий framework и сборщику |
| `name` | Kebab-case имени каталога модуля; для `svg-sprite` и `svg-sprites` — имени родительского каталога | Имя спрайта; в modes с компонентом также задаёт имя компонента и типов |
| `description` | Нет | Описание для типов и Viewer |
| `input` | `./icons` | Каталог, SVG-файл, glob-шаблон или массив источников |
| `transform` | Все включены | Настройки подготовки SVG |
| `generatedNotice` | `true` | Вид предупреждения в generated-файлах |
Пути и glob-шаблоны в `input` считаются от каталога config-файла. Паттерн с префиксом `!` исключает совпадения.
## JavaScript
JavaScript-конфиг экспортирует обычный объект по умолчанию:
```js
export default {
mode: 'react@vite',
name: 'icons',
input: './icons',
}
```
Передайте CLI путь к `.js`-файлу так же, как к JSON:
```bash
npx --yes @gromlab/svg-sprites path/to/svg-sprite.config.js
```
## TypeScript
Для проверки конфига TypeScript установите пакет как dev dependency:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Используйте `defineSpriteConfig`:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'react@vite',
name: 'icons',
input: './icons',
})
```
Или примените `satisfies` с type-only импортом:
```ts
import type { SpriteConfig } from '@gromlab/svg-sprites'
export default {
mode: 'react@vite',
name: 'icons',
input: './icons',
} satisfies SpriteConfig
```
CLI загружает `.ts`-конфиг напрямую:
```bash
npx --yes @gromlab/svg-sprites path/to/svg-sprite.config.ts
```
Полный список modes, CLI-флагов, правил именования и transform-опций находится в [техническом справочнике](reference/technical.md).

78
docs/ru/guides/AGENTS.md Normal file
View File

@@ -0,0 +1,78 @@
# Правила гайдов быстрого старта
## Цель
Гайд должен помочь читателю как можно быстрее создать SVG-спрайт и использовать его в своём приложении.
Спрайт является главным результатом. Компоненты и другие сгенерированные файлы описываются только как средства его использования.
## Область гайда
Каждый гайд посвящён одному exact mode.
В гайд включаются только действия и особенности, относящиеся к этому mode. Нельзя переносить в него поведение других сборщиков, фреймворков или modes.
Все технические утверждения необходимо проверять по реализации соответствующего adapter.
## Структура
Гайд состоит из трёх основных частей:
1. Генерация спрайта.
2. Использование спрайта.
3. Дебаг и превью через Viewer.
Первая строка после заголовка должна объяснять, что это инструкция по быстрому созданию SVG-спрайта и для какого приложения она предназначена.
## Примеры
Все примеры внутри гайда должны составлять один последовательный сценарий.
Пути, имена, команды, импорты и названия сгенерированных API должны соответствовать друг другу и фактическому результату генерации.
Во всех гайдах используются согласованные примеры:
- исходные SVG находятся в `assets/svg-icons`;
- спрайт создаётся в `assets/app-icons`;
- конфиг записывается в JSON;
- имя спрайта в конфиге — `app`.
## Зависимости
В разделе генерации нужно явно показать ключевое преимущество: для создания и использования спрайта пакет не требуется добавлять в зависимости проекта.
Viewer описывается отдельно как необязательный инструмент разработки. Установка или подключение пакета допускается только в разделе Viewer и только способом, подходящим текущему mode.
## Содержание
Гайд должен содержать только минимальный рабочий путь:
- структуру проекта;
- конфиг;
- команду генерации;
- автоматическую генерацию перед запуском и сборкой, если она необходима;
- подключение иконки;
- базовую настройку размера и цветов;
- подключение Viewer.
Особенности mode добавляются только тогда, когда без них пример не работает или работает неправильно.
## Технический шум
Не нужно описывать внутреннее устройство генератора, сгенерированных файлов и сборщика.
Не нужно перечислять альтернативные конфигурации, дополнительные API, редкие сценарии и ограничения, не относящиеся к быстрому старту.
Подробности должны оставаться в reference-документации.
## Стиль
Писать для пользователя, а не для разработчика библиотеки.
Использовать короткие, прямые и практические формулировки.
Сначала объяснять пользу или цель шага, затем показывать действие.
Не использовать воду, рекламные формулировки и технические термины, которые не помогают выполнить инструкцию.
Не начинать документ с перечисления сгенерированных компонентов или особенностей реализации.

View File

@@ -1,153 +1,108 @@
# Next.js App Router с Turbopack
# SVG-спрайт для Next.js App Router с Turbopack
Это автономный quick start для exact mode key `next@app/turbopack`: generated `IconsIcon` совместим с Server Components и asset pipeline Turbopack.
Инструкция по быстрому созданию SVG-спрайта в приложении Next.js с App Router и Turbopack.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный plain config:
```ts
export default {
mode: 'next@app/turbopack',
name: 'icons',
```json
{
"mode": "next@app/turbopack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Конфиг может быть `.ts`, `.js` с `default export` или `.json`.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
В CI зафиксируйте точную версию, например `@gromlab/svg-sprites@1.1.5`. Mode и команды Next должны указывать один bundler:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && next dev --turbopack",
"build": "npm run sprites && next build --turbopack",
"start": "next start",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "next dev --turbopack",
"prebuild": "npm run sprites",
"build": "next build --turbopack"
}
}
```
Не добавляйте одновременно `predev`/`prebuild` и явный `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Его `.d.ts` self-contained и не импортируют generator package.
## Использование спрайта
Значение `name: "app"` создаёт React-компонент `AppIcon`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Generated icon не содержит `'use client'`, поэтому его можно импортировать прямо в Server Component:
Используйте компонент в Server Component:
```tsx
// app/page.tsx
import { IconsIcon, iconsIconNames } from '../src/sprite'
import { AppIcon } from '../assets/app-icons'
export default function Page() {
return (
<main>
<IconsIcon
<AppIcon
icon="check"
width={24}
height={24}
role="img"
aria-label="Готово"
style={{ '--icon-color-1': '#16a34a' }}
style={{
color: '#334155',
'--icon-color-2': '#f59e0b',
}}
/>
<span>{iconsIconNames.length} иконок</span>
</main>
)
}
```
Turbopack обрабатывает generated `new URL('../sprite.svg', import.meta.url).href` и выпускает внешний hashed asset. Не добавляйте Client Component boundary только ради `IconsIcon`.
Для `AppIcon` не нужен `'use client'`. Turbopack сам добавляет `sprite.svg` в итоговую сборку, поэтому переносить его в `public` не нужно.
## 2. Дебаг и превью
## Дебаг и превью
Viewer необязателен и нужен только для debug/preview:
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки и устанавливается отдельно:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Viewer интерактивен, поэтому создайте для него отдельный Client Component:
Создайте Client Component `app/svg-sprite/SvgSpriteViewer.tsx`:
```tsx
// app/icons-debug/sprite-viewer.tsx
'use client'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('../../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
() => import('../../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'),
] as const
export function AppSpriteViewer() {
export function SvgSpriteViewer() {
return <SpriteViewer sources={sources} title="Иконки проекта" />
}
```
Server page импортирует только эту boundary:
Создайте маршрут `app/svg-sprite/page.tsx`:
```tsx
// app/icons-debug/page.tsx
import { AppSpriteViewer } from './sprite-viewer'
import { notFound } from 'next/navigation'
export default function IconsDebugPage() {
return <AppSpriteViewer />
import { SvgSpriteViewer } from './SvgSpriteViewer'
export default function SvgSpritePage() {
if (process.env.NODE_ENV !== 'development') notFound()
return <SvgSpriteViewer />
}
```
Viewer не входит в production icon runtime и не нужен обычным страницам с `IconsIcon`.
## 3. Типизация конфига
После локальной установки package используйте helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'next@app/turbopack',
name: 'icons',
})
```
Возможен и type-only import `SpriteConfig` с `satisfies SpriteConfig`.
Без package добавьте локальный type в config:
```ts
type LocalSpriteConfig = {
mode: 'next@app/turbopack'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'next@app/turbopack',
name: 'icons',
} satisfies LocalSpriteConfig
```
Exact literal защищает от смешивания App Router и других bundler contracts.
Запустите `npm run dev` и откройте `/svg-sprite`. В production маршрут вернёт 404.

View File

@@ -1,151 +1,108 @@
# Next.js App Router с Webpack
# SVG-спрайт для Next.js App Router с Webpack
Это автономный quick start для exact mode key `next@app/webpack`: generated `IconsIcon` совместим с Server Components и Webpack pipeline Next.js.
Инструкция по быстрому созданию SVG-спрайта в приложении Next.js с App Router и Webpack.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный plain config:
```ts
export default {
mode: 'next@app/webpack',
name: 'icons',
```json
{
"mode": "next@app/webpack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Также поддерживаются `.js` с `default export` и `.json`.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
В CI замените `latest` точной версией, например `@gromlab/svg-sprites@1.1.5`. Exact Next commands для этого mode:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && next dev --webpack",
"build": "npm run sprites && next build --webpack",
"start": "next start",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "next dev --webpack",
"prebuild": "npm run sprites",
"build": "next build --webpack"
}
}
```
Не сочетайте явный `npm run sprites` с `predev` или `prebuild`. `.svg-sprite` generated и не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated declarations self-contained и не зависят от `@gromlab/svg-sprites`.
## Использование спрайта
Значение `name: "app"` создаёт React-компонент `AppIcon`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production usage в Server Component:
Используйте компонент в Server Component:
```tsx
// app/page.tsx
import { IconsIcon, iconsIconNames } from '../src/sprite'
import { AppIcon } from '../assets/app-icons'
export default function Page() {
return (
<main>
<IconsIcon
<AppIcon
icon="check"
width={24}
height={24}
role="img"
aria-label="Готово"
style={{ '--icon-color-1': '#16a34a' }}
style={{
color: '#334155',
'--icon-color-2': '#f59e0b',
}}
/>
<span>{iconsIconNames.length} иконок</span>
</main>
)
}
```
Generated component не содержит `'use client'`. Next Webpack обрабатывает `new URL('../sprite.svg', import.meta.url).href` и публикует отдельный SVG asset; не переписывайте этот URL и не переносите sprite в `public` вручную.
Для `AppIcon` не нужен `'use client'`. Next.js сам добавляет `sprite.svg` в итоговую сборку, поэтому переносить его в `public` не нужно.
## 2. Дебаг и превью
## Дебаг и превью
Viewer необязателен. Для debug/preview установите package:
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки и устанавливается отдельно:
```bash
npm install --save-dev @gromlab/svg-sprites
```
App Router требует отдельную Client Component boundary для Viewer:
Создайте Client Component `app/svg-sprite/SvgSpriteViewer.tsx`:
```tsx
// app/icons-debug/sprite-viewer.tsx
'use client'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('../../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
() => import('../../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'),
] as const
export function AppSpriteViewer() {
export function SvgSpriteViewer() {
return <SpriteViewer sources={sources} title="Иконки проекта" />
}
```
Создайте маршрут `app/svg-sprite/page.tsx`:
```tsx
// app/icons-debug/page.tsx
import { AppSpriteViewer } from './sprite-viewer'
import { notFound } from 'next/navigation'
export default function IconsDebugPage() {
return <AppSpriteViewer />
import { SvgSpriteViewer } from './SvgSpriteViewer'
export default function SvgSpritePage() {
if (process.env.NODE_ENV !== 'development') notFound()
return <SvgSpriteViewer />
}
```
Статический loader позволяет Webpack связать manifest и emitted SVG. Viewer не входит в production runtime `IconsIcon`.
## 3. Типизация конфига
При локально установленном package используйте helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'next@app/webpack',
name: 'icons',
})
```
Другой package-вариант: type-only import `SpriteConfig` и `satisfies SpriteConfig`.
Без package вставьте локальный type прямо в config:
```ts
type LocalSpriteConfig = {
mode: 'next@app/webpack'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'next@app/webpack',
name: 'icons',
} satisfies LocalSpriteConfig
```
Локальный exact literal исключает случайную генерацию Turbopack или Pages Router output.
Запустите `npm run dev` и откройте `/svg-sprite`. В production маршрут вернёт 404.

View File

@@ -1,140 +1,98 @@
# Next.js Pages Router с Turbopack
# SVG-спрайт для Next.js Pages Router с Turbopack
Это автономный quick start для exact mode key `next@pages/turbopack`: generated `IconsIcon` работает при SSR, SSG и клиентских переходах Pages Router.
Инструкция по быстрому созданию SVG-спрайта в приложении Next.js с Pages Router и Turbopack.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный plain config:
```ts
export default {
mode: 'next@pages/turbopack',
name: 'icons',
```json
{
"mode": "next@pages/turbopack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Конфиг также может быть `.js` с `default export` или `.json`.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
Для CI зафиксируйте точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact commands должны сохранять Turbopack и для dev, и для production build:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && next dev --turbopack",
"build": "npm run sprites && next build --turbopack",
"start": "next start",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "next dev --turbopack",
"prebuild": "npm run sprites",
"build": "next build --turbopack"
}
}
```
Не добавляйте `predev`/`prebuild`, если scripts уже явно вызывают `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated `.d.ts` self-contained и не импортируют generator package.
## Использование спрайта
Значение `name: "app"` создаёт React-компонент `AppIcon`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production usage на обычной page:
Используйте компонент на странице:
```tsx
// pages/index.tsx
import { IconsIcon, iconsIconNames } from '../src/sprite'
import { AppIcon } from '../assets/app-icons'
export default function Page() {
return (
<main>
<IconsIcon
<AppIcon
icon="check"
width={24}
height={24}
role="img"
aria-label="Готово"
style={{ '--icon-color-1': '#16a34a' }}
style={{
color: '#334155',
'--icon-color-2': '#f59e0b',
}}
/>
<span>{iconsIconNames.length} иконок</span>
</main>
)
}
```
Компонент одинаково работает с `getServerSideProps`, `getStaticProps` и client navigation. Turbopack разрешает generated `new URL('../sprite.svg', import.meta.url).href` в отдельный hashed asset.
Компонент работает с SSR, SSG и клиентскими переходами. Turbopack сам добавляет `sprite.svg` в итоговую сборку, поэтому переносить его в `public` не нужно.
## 2. Дебаг и превью
## Дебаг и превью
Viewer необязателен и нужен только для debug/preview:
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки и устанавливается отдельно:
```bash
npm install --save-dev @gromlab/svg-sprites
```
В Pages Router Viewer можно использовать прямо в page, без отдельной App Router Client Component boundary:
Создайте страницу `pages/svg-sprite.tsx`:
```tsx
// pages/icons-debug.tsx
import type { GetStaticProps } from 'next'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
() => import('../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'),
] as const
export default function IconsDebugPage() {
export default function SvgSpritePage() {
return <SpriteViewer sources={sources} title="Иконки проекта" />
}
export const getStaticProps: GetStaticProps = () =>
process.env.NODE_ENV === 'development'
? { props: {} }
: { notFound: true }
```
Оставляйте эту page только во внутреннем debug-разделе. Viewer не входит в production icon runtime `IconsIcon`.
## 3. Типизация конфига
Если package установлен локально, используйте helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'next@pages/turbopack',
name: 'icons',
})
```
Альтернатива: type-only import `SpriteConfig` и объект `satisfies SpriteConfig`.
Без package добавьте copy-paste type в config:
```ts
type LocalSpriteConfig = {
mode: 'next@pages/turbopack'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'next@pages/turbopack',
name: 'icons',
} satisfies LocalSpriteConfig
```
Exact literal не позволяет незаметно смешать Pages Router с App Router или Webpack output.
Запустите `npm run dev` и откройте `/svg-sprite`. В production маршрут вернёт 404.

View File

@@ -1,140 +1,98 @@
# Next.js Pages Router с Webpack
# SVG-спрайт для Next.js Pages Router с Webpack
Это автономный quick start для exact mode key `next@pages/webpack`: generated `IconsIcon` работает в Pages Router и публикует SVG через Webpack pipeline Next.js.
Инструкция по быстрому созданию SVG-спрайта в приложении Next.js с Pages Router и Webpack.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный plain config:
```ts
export default {
mode: 'next@pages/webpack',
name: 'icons',
```json
{
"mode": "next@pages/webpack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Поддерживаются `.ts`, `.js` с `default export` и `.json` configs.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
В CI замените `latest` на точную проверенную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Next commands для Webpack:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && next dev --webpack",
"build": "npm run sprites && next build --webpack",
"start": "next start",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "next dev --webpack",
"prebuild": "npm run sprites",
"build": "next build --webpack"
}
}
```
Не дублируйте эти вызовы через `predev`, `prebuild` или `pretypecheck`. `.svg-sprite` generated и не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated declarations self-contained и не требуют `@gromlab/svg-sprites`.
## Использование спрайта
Значение `name: "app"` создаёт React-компонент `AppIcon`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production usage:
Используйте компонент на странице:
```tsx
// pages/index.tsx
import { IconsIcon, iconsIconNames } from '../src/sprite'
import { AppIcon } from '../assets/app-icons'
export default function Page() {
return (
<main>
<IconsIcon
<AppIcon
icon="check"
width={24}
height={24}
role="img"
aria-label="Готово"
style={{ '--icon-color-1': '#16a34a' }}
style={{
color: '#334155',
'--icon-color-2': '#f59e0b',
}}
/>
<span>{iconsIconNames.length} иконок</span>
</main>
)
}
```
Компонент поддерживает SSR, SSG и клиентские переходы. Next Webpack преобразует generated `new URL('../sprite.svg', import.meta.url).href` во внешний hashed asset; не конструируйте URL спрайта вручную.
Компонент работает с SSR, SSG и клиентскими переходами. Next.js сам добавляет `sprite.svg` в итоговую сборку, поэтому переносить его в `public` не нужно.
## 2. Дебаг и превью
## Дебаг и превью
Viewer необязателен. Устанавливайте package только для debug/preview:
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки и устанавливается отдельно:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Pages Router позволяет разместить Viewer непосредственно в page без отдельной App Router boundary:
Создайте страницу `pages/svg-sprite.tsx`:
```tsx
// pages/icons-debug.tsx
import type { GetStaticProps } from 'next'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
() => import('../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'),
] as const
export default function IconsDebugPage() {
export default function SvgSpritePage() {
return <SpriteViewer sources={sources} title="Иконки проекта" />
}
export const getStaticProps: GetStaticProps = () =>
process.env.NODE_ENV === 'development'
? { props: {} }
: { notFound: true }
```
Статический loader даёт Webpack точный manifest module и связанный SVG asset. Не импортируйте Viewer из production pages, если preview там не нужен; runtime `IconsIcon` от него независим.
## 3. Типизация конфига
После локальной установки package доступен helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'next@pages/webpack',
name: 'icons',
})
```
Также можно применить `satisfies SpriteConfig` с type-only импортом `SpriteConfig`.
Без package вставьте локальный type прямо в config:
```ts
type LocalSpriteConfig = {
mode: 'next@pages/webpack'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'next@pages/webpack',
name: 'icons',
} satisfies LocalSpriteConfig
```
Такой exact literal выявляет ошибочный выбор App Router или Turbopack ещё при проверке config.
Запустите `npm run dev` и откройте `/svg-sprite`. В production маршрут вернёт 404.

View File

@@ -1,141 +1,115 @@
# React-компонент для Vite
# SVG-спрайт для React на Vite
Это автономный quick start для exact mode key `react@vite`: генератор создаёт типизированный `IconsIcon`, а Vite публикует отдельный SVG asset.
Инструкция по быстрому созданию SVG-спрайта в React-приложении на Vite.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный plain config:
```ts
export default {
mode: 'react@vite',
name: 'icons',
```json
{
"mode": "react@vite",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Вместо `.ts` можно использовать `.js` с `default export` или `.json`.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
В CI замените `latest` на точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Vite commands:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && vite",
"build": "npm run sprites && tsc --noEmit && vite build",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "vite",
"prebuild": "npm run sprites",
"build": "tsc --noEmit && vite build"
}
}
```
Не добавляйте `predev`, `prebuild` или `pretypecheck`, если соответствующие scripts уже явно запускают `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated declarations self-contained: они описывают компонент и manifest без импорта `@gromlab/svg-sprites`.
## Использование спрайта
Пользовательский barrel возвращает generated API:
Значение `name: "app"` создаёт React-компонент `AppIcon`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production usage:
Используйте компонент в приложении:
```tsx
import { IconsIcon, iconsIconNames } from './sprite'
import { AppIcon } from '../assets/app-icons'
export function SaveButton() {
export function SaveIcon() {
return (
<button type="button">
<IconsIcon
<AppIcon
icon="check"
width={24}
height={24}
aria-hidden="true"
style={{ '--icon-color-1': '#16a34a' }}
role="img"
aria-label="Готово"
style={{
color: '#334155',
'--icon-color-2': '#f59e0b',
}}
/>
Сохранить
</button>
)
}
console.log(iconsIconNames)
```
Prop `icon` является union имён исходных файлов. Vite автоматически обрабатывает generated CSS Module и импорт `sprite.svg?no-inline`; query запрещает inline и заставляет Vite выпустить отдельный hashed SVG asset. Если TypeScript не знает Vite asset imports, добавьте `/// <reference types="vite/client" />` в `src/vite-env.d.ts`.
Свойство `icon` принимает имена исходных SVG без расширения. Монохромная иконка наследует `color`, а цвета многоцветной переопределяются через `--icon-color-N`.
## 2. Дебаг и превью
Vite сам подключает стили компонента и добавляет `sprite.svg` в итоговую сборку.
Viewer необязателен и нужен только для debug/preview. Установите package отдельно:
## Дебаг и превью
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки и устанавливается отдельно:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Используйте React bridge со статическим массивом loaders:
Создайте `svg-sprite.html` в корне проекта:
```html
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Иконки проекта</title>
</head>
<body>
<!-- React-корень Viewer для дебага и превью SVG-спрайта -->
<div id="svg-sprite-viewer"></div>
<!-- Подключение создаваемого ниже скрипта дебаггера -->
<script type="module" src="/src/svg-sprite-debug.tsx"></script>
</body>
</html>
```
Создайте `src/svg-sprite-debug.tsx`:
```tsx
import { createRoot } from 'react-dom/client'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('./sprite/.svg-sprite/svg-sprite.manifest.js'),
() => import('../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'),
] as const
export function IconsDebugPage() {
return <SpriteViewer sources={sources} title="Иконки проекта" />
}
createRoot(document.getElementById('svg-sprite-viewer')!).render(
<SpriteViewer sources={sources} title="Иконки проекта" />,
)
```
Строковый путь в `import()` должен указывать на generated JS manifest. Держите страницу за debug-маршрутом; `SpriteViewer` не входит в production runtime `IconsIcon`.
Запустите `npm run dev` и откройте `/svg-sprite.html`.
## 3. Типизация конфига
Если package установлен локально, используйте helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'react@vite',
name: 'icons',
})
```
Также можно импортировать `SpriteConfig` только как type и написать объект `satisfies SpriteConfig`.
Без package добавьте локальный type прямо в config:
```ts
type LocalSpriteConfig = {
mode: 'react@vite'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'react@vite',
name: 'icons',
} satisfies LocalSpriteConfig
```
Локальный type проверяет только этот exact mode и не создаёт runtime-зависимость.
Стандартная production-сборка Vite использует только `index.html` и не включает страницу Viewer.

View File

@@ -1,141 +1,126 @@
# React-компонент для Webpack 5
# SVG-спрайт для React на Webpack 5
Это автономный quick start для exact mode key `react@webpack`: generated `IconsIcon` использует Webpack 5 Asset Modules и CSS Modules.
Инструкция по быстрому созданию SVG-спрайта в React-приложении на Webpack 5.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный plain config:
```ts
export default {
mode: 'react@webpack',
name: 'icons',
```json
{
"mode": "react@webpack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Поддерживаются `.ts`, `.js` с `default export` и `.json` configs.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
В CI замените `latest` на точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Webpack commands:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && webpack serve --mode development",
"build": "npm run sprites && webpack --mode production",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "webpack serve --mode development",
"prebuild": "npm run sprites",
"build": "webpack --mode production"
}
}
```
Не сочетайте эти явные вызовы с `predev`/`prebuild`: иначе генерация задублируется. `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated `.d.ts` self-contained и не импортируют generator package.
## Использование спрайта
Значение `name: "app"` создаёт React-компонент `AppIcon`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production usage:
Используйте компонент в приложении:
```tsx
import { IconsIcon, iconsIconNames } from './sprite'
import { AppIcon } from '../assets/app-icons'
export function SaveButton() {
export function SaveIcon() {
return (
<button type="button">
<IconsIcon
<AppIcon
icon="check"
width={24}
height={24}
aria-hidden="true"
style={{ '--icon-color-1': '#16a34a' }}
role="img"
aria-label="Готово"
style={{
color: '#334155',
'--icon-color-2': '#f59e0b',
}}
/>
Сохранить
</button>
)
}
console.log(iconsIconNames)
```
Generated component получает URL через `new URL('../sprite.svg', import.meta.url).href`. Webpack 5 должен обработать SVG как Asset Module. Исключите generated `sprite.svg` из `@svgr/webpack`, inline/raw loaders и других общих SVG rules либо задайте для него `type: 'asset/resource'`.
Свойство `icon` принимает имена исходных SVG без расширения. Монохромная иконка наследует `color`, а цвета многоцветной переопределяются через `--icon-color-N`.
Компонент импортирует `react-component.module.css`. Webpack config должен обрабатывать `*.module.css` через `css-loader` с CSS Modules и `style-loader` или `MiniCssExtractPlugin`. Для TypeScript при необходимости добавьте декларацию `declare module '*.module.css'`.
Компонент использует CSS Modules. Если проект ещё не обрабатывает их с default export, добавьте правило в `webpack.config.js`:
## 2. Дебаг и превью
```js
{
test: /\.module\.css$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: { modules: { namedExport: false } },
},
],
}
```
Viewer необязателен. Устанавливайте package только для debug/preview:
Webpack 5 сам добавляет `sprite.svg` в итоговую сборку.
## Дебаг и превью
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки.
Установите Viewer:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Webpack не использует `import.meta.glob`; передайте статический loader:
Создайте entry `src/svg-sprite-debug.tsx`:
```tsx
import { createRoot } from 'react-dom/client'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('./sprite/.svg-sprite/svg-sprite.manifest.js'),
() => import('../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'),
] as const
export function IconsDebugPage() {
return <SpriteViewer sources={sources} title="Иконки проекта" />
}
const container = document.createElement('div')
document.body.append(container)
createRoot(container).render(
<SpriteViewer sources={sources} title="Иконки проекта" />,
)
```
Webpack создаст chunk manifest и разрешит его SVG через тот же Asset Modules pipeline. Viewer держите только в debug route; production `IconsIcon` от него не зависит.
Добавьте скрипт к основному entry только в development-режиме. Сохраните остальные настройки `webpack.config.js`:
## 3. Типизация конфига
С локально установленным package доступен helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'react@webpack',
name: 'icons',
```js
export default (_env, argv) => ({
// Остальные настройки Webpack.
entry: [
'./src/main.tsx',
...(argv.mode === 'development' ? ['./src/svg-sprite-debug.tsx'] : []),
],
})
```
Эквивалентная проверка: type-only import `SpriteConfig` и `satisfies SpriteConfig`.
Без package используйте copy-paste type в config:
```ts
type LocalSpriteConfig = {
mode: 'react@webpack'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'react@webpack',
name: 'icons',
} satisfies LocalSpriteConfig
```
Локальный literal не разрешит случайно выбрать Vite или Next mode.
Запустите `npm run dev`. Viewer появится на основной странице приложения и не попадёт в production-сборку.

View File

@@ -1,151 +1,114 @@
# Нативный icon Web Component с Vite
# SVG-спрайт для Vite без фреймворка
Это автономный quick start для exact mode key `standalone@vite`: generated facade регистрирует `<icons-icon>` и отдаёт SVG в asset pipeline Vite.
Инструкция по быстрому созданию SVG-спрайта в приложении на Vite без фреймворка.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
Рекомендуемая структура держит конфиг и иконки рядом:
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
```text
src/sprite/
├── icons/
├── check.svg
└── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Минимальный plain config:
```ts
export default {
mode: 'standalone@vite',
name: 'icons',
```json
{
"mode": "standalone@vite",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Конфиг также может быть `.js` с `default export` или `.json`.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
В CI замените `latest` на точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact dev/build commands для Vite:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && vite",
"build": "npm run sprites && vite build",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "vite",
"prebuild": "npm run sprites",
"build": "vite build"
}
}
```
Не добавляйте одновременно `predev`/`prebuild` и явный `npm run sprites` в этих scripts. `.svg-sprite` является generated-каталогом и не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated `.d.ts` self-contained и не импортируют `@gromlab/svg-sprites`.
## Использование спрайта
Верните facade через пользовательский barrel:
Значение `name: "app"` создаёт элемент `<app-icon>`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production entry регистрирует native Web Component:
Зарегистрируйте элемент в `src/main.ts`:
```ts
import { defineIconsIconElement, iconsIconNames } from './sprite'
import { defineAppIconElement } from '../assets/app-icons'
import './style.css'
defineIconsIconElement()
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<icons-icon icon="check" role="img" aria-label="Готово"></icons-icon>
`
console.log(iconsIconNames)
defineAppIconElement()
```
Generated facade импортирует `sprite.svg?no-inline`: Vite автоматически выпускает отдельный hashed SVG asset и не превращает его в data URL. TypeScript-проекту при необходимости добавьте стандартные Vite types:
Используйте иконку в HTML:
```ts
/// <reference types="vite/client" />
```html
<app-icon icon="check" role="img" aria-label="Готово"></app-icon>
```
Размер по умолчанию равен `1em`, поэтому компонент удобно масштабировать через `font-size`. Цвет задаётся через `color` и generated custom properties:
Файл `check.svg` доступен как `icon="check"`. Размер и цвета настраиваются через CSS:
```css
icons-icon {
app-icon {
font-size: 24px;
color: #334155;
--icon-color-2: #f59e0b;
}
```
## 2. Дебаг и превью
Монохромная иконка наследует `color`, а цвета многоцветной иконки переопределяются через `--icon-color-N`. Нужные переменные показывает Viewer.
Viewer необязателен и нужен только для debug/preview. Установите его отдельно:
Vite сам добавит `sprite.svg` в итоговую сборку. Копировать его в `public` не нужно.
## Дебаг и превью
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки и устанавливается отдельно:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Зарегистрируйте Viewer и передайте generated JS manifest через свойство `sources`:
Создайте `svg-sprite.html` в корне проекта:
```html
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Иконки проекта</title>
</head>
<body>
<!-- Компонент Viewer для дебага и превью SVG-спрайта -->
<gromlab-sprite-viewer viewer-title="Иконки проекта"></gromlab-sprite-viewer>
<!-- Подключение создаваемого ниже скрипта дебаггера -->
<script type="module" src="/src/svg-sprite-debug.ts"></script>
</body>
</html>
```
Создайте `src/svg-sprite-debug.ts`:
```ts
import '@gromlab/svg-sprites/viewer/element'
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
import spriteManifest from './sprite/.svg-sprite/svg-sprite.manifest.js'
document.querySelector<HTMLDivElement>('#app')!.insertAdjacentHTML(
'beforeend',
'<gromlab-sprite-viewer></gromlab-sprite-viewer>',
)
import spriteManifest from '../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
viewer.viewerTitle = 'Иконки проекта'
viewer.sources = [spriteManifest]
```
Расположите этот код только в debug entry или внутреннем маршруте. Viewer не входит в production runtime `<icons-icon>`.
Запустите `npm run dev` и откройте `/svg-sprite.html`.
## 3. Типизация конфига
При локально установленном package используйте helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'standalone@vite',
name: 'icons',
})
```
Альтернатива с package: `import type { SpriteConfig }` и объект `satisfies SpriteConfig`.
Без package скопируйте локальный type прямо в config:
```ts
type LocalSpriteConfig = {
mode: 'standalone@vite'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'standalone@vite',
name: 'icons',
} satisfies LocalSpriteConfig
```
Локальный type ограничивает `mode` одним exact literal и ничего не загружает во время генерации.
Viewer не требуется для работы `<app-icon>` и не подключается к основному коду приложения.

View File

@@ -1,145 +1,111 @@
# Нативный icon Web Component с Webpack 5
# SVG-спрайт для Webpack 5 без фреймворка
Это автономный quick start для exact mode key `standalone@webpack`: generated facade предоставляет `<icons-icon>`, а Webpack 5 публикует SVG через Asset Modules.
Инструкция по быстрому созданию SVG-спрайта в приложении на Webpack 5 без фреймворка.
## 1. Генерация спрайта
## Генерация спрайта
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
Выберите папку для спрайта. В примере используется `assets/app-icons`, а исходные SVG находятся в `assets/svg-icons`.
```text
src/sprite/
├── icons/
│ ├── check.svg
│ └── warning.svg
├── index.ts
└── svg-sprite.config.ts
```
Создайте конфиг `assets/app-icons/svg-sprite.config.json`:
Минимальный config рядом с `icons/`:
```ts
export default {
mode: 'standalone@webpack',
name: 'icons',
```json
{
"mode": "standalone@webpack",
"name": "app",
"input": "../svg-icons/**/*.svg"
}
```
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Поддерживаются также `.js` с `default export` и `.json`.
Путь в `input` считается от папки с конфигом.
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
```
Для CI закрепите точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Webpack commands:
Добавьте команды генерации в `package.json`. Сгенерированные файлы по умолчанию исключены из Git, поэтому `predev` и `prebuild` пересобирают спрайт перед каждым запуском и сборкой:
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
"dev": "npm run sprites && webpack serve --mode development",
"build": "npm run sprites && webpack --mode production",
"typecheck": "npm run sprites && tsc --noEmit"
"sprites": "npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json",
"predev": "npm run sprites",
"dev": "webpack serve --mode development",
"prebuild": "npm run sprites",
"build": "webpack --mode production"
}
}
```
Не дублируйте запуск через `predev`/`prebuild`, если scripts уже явно вызывают `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Его declarations self-contained и не требуют `@gromlab/svg-sprites`.
## Использование спрайта
Значение `name: "app"` создаёт элемент `<app-icon>`.
Создайте точку входа `assets/app-icons/index.ts`:
```ts
// src/sprite/index.ts
export * from './.svg-sprite/index.js'
```
Production usage:
Зарегистрируйте элемент в основном entry приложения:
```ts
import { defineIconsIconElement, iconsIconNames } from './sprite'
import { defineAppIconElement } from '../assets/app-icons'
import './style.css'
defineIconsIconElement()
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<icons-icon icon="check" role="img" aria-label="Готово"></icons-icon>
`
console.log(iconsIconNames)
defineAppIconElement()
```
Generated facade использует `new URL('./sprite.svg', import.meta.url).href`. Webpack 5 Asset Modules выпускают отдельный asset; его итоговый URL учитывает `output.publicPath` и `assetModuleFilename`.
Используйте иконку в HTML:
Если проект использует `@svgr/webpack`, `svg-inline-loader`, `raw-loader` или общий SVG rule, исключите `src/sprite/.svg-sprite/sprite.svg` из этого правила. Generated SVG должен обрабатываться как `asset/resource`, а не как React-компонент или inline source.
```html
<app-icon icon="check" role="img" aria-label="Готово"></app-icon>
```
Размер Web Component по умолчанию `1em`; управляйте им и цветами обычным CSS:
Файл `check.svg` доступен как `icon="check"`. Размер и цвета настраиваются через CSS:
```css
icons-icon {
app-icon {
font-size: 24px;
color: #334155;
--icon-color-2: #f59e0b;
}
```
## 2. Дебаг и превью
Монохромная иконка наследует `color`, а цвета многоцветной иконки переопределяются через `--icon-color-N`. Нужные переменные показывает Viewer.
Viewer необязателен. Для debug/preview установите package как dev dependency:
Webpack 5 сам добавит `sprite.svg` в итоговую сборку.
## Дебаг и превью
Viewer показывает все иконки на одной странице, позволяет проверить их отображение, изменить цвета и посмотреть связанные CSS-переменные. Он нужен только для разработки.
Установите Viewer:
```bash
npm install --save-dev @gromlab/svg-sprites
```
Подключите element entry и generated JS manifest:
Создайте entry `src/svg-sprite-debug.ts`:
```ts
import '@gromlab/svg-sprites/viewer/element'
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
import spriteManifest from './sprite/.svg-sprite/svg-sprite.manifest.js'
import spriteManifest from '../assets/app-icons/.svg-sprite/svg-sprite.manifest.js'
document.querySelector<HTMLDivElement>('#app')!.insertAdjacentHTML(
'beforeend',
'<gromlab-sprite-viewer></gromlab-sprite-viewer>',
)
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
const viewer = document.createElement('gromlab-sprite-viewer') as SpriteViewerElement
viewer.viewerTitle = 'Иконки проекта'
viewer.sources = [spriteManifest]
document.body.append(viewer)
```
Webpack свяжет manifest с тем же emitted SVG asset. Оставляйте Viewer только в debug entry: production `<icons-icon>` от него не зависит.
Добавьте скрипт к основному entry только в development-режиме. Сохраните остальные настройки `webpack.config.js`:
## 3. Типизация конфига
После локальной установки package можно использовать helper:
```ts
import { defineSpriteConfig } from '@gromlab/svg-sprites'
export default defineSpriteConfig({
mode: 'standalone@webpack',
name: 'icons',
```js
export default (_env, argv) => ({
// Остальные настройки Webpack.
entry: [
'./src/main.ts',
...(argv.mode === 'development' ? ['./src/svg-sprite-debug.ts'] : []),
],
})
```
Либо импортируйте только `SpriteConfig` как type и примените `satisfies SpriteConfig`.
Запустите `npm run dev`. Viewer появится на основной странице приложения.
Без package добавьте copy-paste type в сам config:
```ts
type LocalSpriteConfig = {
mode: 'standalone@webpack'
name?: string
description?: string
input?: string | string[]
transform?: {
removeSize?: boolean
replaceColors?: boolean
addTransition?: boolean
}
generatedNotice?: boolean
}
export default {
mode: 'standalone@webpack',
name: 'icons',
} satisfies LocalSpriteConfig
```
Этот вариант сохраняет проверку exact mode без runtime import и без записи generator package в проект.
Viewer добавляется только в development-сборку и не попадает в production.

View File

@@ -1,4 +0,0 @@
# Guides Next.js App Router перемещены
- [App Router + Turbopack](guides/next-app-turbopack.md)
- [App Router + Webpack](guides/next-app-webpack.md)

View File

@@ -1,4 +0,0 @@
# Guides Next.js Pages Router перемещены
- [Pages Router + Turbopack](guides/next-pages-turbopack.md)
- [Pages Router + Webpack](guides/next-pages-webpack.md)

View File

@@ -1,3 +0,0 @@
# Программный API перемещён
Canonical документ: [программный API](reference/programmatic-api.md).

View File

@@ -1,3 +0,0 @@
# Guide React + Vite перемещён
Canonical guide: [React + Vite](guides/react-vite.md).

View File

@@ -1,3 +0,0 @@
# Guide React + Webpack перемещён
Canonical guide: [React + Webpack](guides/react-webpack.md).

View File

@@ -1,3 +0,0 @@
# Технический справочник перемещён
Canonical документ: [технический справочник](reference/technical.md).

View File

@@ -14,6 +14,21 @@ const result = await generateSprite(
)
```
Результат содержит имя и mode спрайта, количество иконок и абсолютные filesystem paths:
```ts
result.name
result.mode
result.target
result.iconCount
result.rootDir
result.generatedDir
result.spritePath
result.manifestPath
```
Next.js modes дополнительно возвращают `router` и `bundler`.
Для static standalone mode `result.spritePath` можно использовать в build-скрипте,
чтобы опубликовать SVG по URL приложения:
@@ -29,7 +44,7 @@ await copyFile(result.spritePath, 'dist/app-icons/sprite.svg')
`spritePath` является filesystem path, а не browser URL. Deployment-neutral JSON
manifest доступен через `result.manifestPath` и копируется независимо от SVG.
Первый аргумент принимает полный путь к config-файлу с любым именем и расширением `.ts`, `.js` или `.json`. Каталог вместо файла включает config-less режим: корнем sprite-модуля становится этот каталог.
Первый аргумент принимает абсолютный или относительный путь к config-файлу с любым именем и расширением `.ts`, `.js` или `.json`. Каталог вместо файла включает config-less режим: корнем sprite-модуля становится этот каталог.
Второй аргумент содержит необязательные overrides и всегда имеет приоритет над конфигом:
@@ -107,13 +122,17 @@ await generateNextSprite('path/to/config.ts', {
```ts
import {
isSpriteMode,
loadSpriteConfig,
resolveSpriteConfig,
resolveSpriteConfigSource,
validateSpriteConfig,
} from '@gromlab/svg-sprites'
```
- `isSpriteMode(value)` проверяет, является ли значение поддерживаемым exact mode.
- `loadSpriteConfig(file)` загружает явно указанный `.ts`, `.js` или `.json` файл.
- `resolveSpriteConfigSource(source)` разрешает путь как config-файл или config-less каталог.
- `validateSpriteConfig(value)` выполняет runtime-валидацию объекта.
- `resolveSpriteConfig(root, config, overrides)` объединяет значения, добавляет defaults и разрешает пути относительно `root`.
@@ -138,6 +157,16 @@ import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
Browser entry регистрирует `<gromlab-sprite-viewer>`. Bare standalone также может загрузить самостоятельный `dist/viewer-element.js` без bundler.
Для ручной регистрации импортируйте runtime без auto-register entry:
```ts
import { defineSpriteViewerElement } from '@gromlab/svg-sprites/viewer'
defineSpriteViewerElement()
```
Этот entry также экспортирует типы `SpriteViewerElement`, `SpriteViewerManifest`, `SpriteViewerSource`, `SpriteViewerSources` и связанные типы manifest и loaders.
React bridge сохраняет компонентный API:
```tsx

View File

@@ -2,6 +2,8 @@
[Индекс документации](../README.md)
[Конфигурация JSON, JavaScript и TypeScript](../configuration.md)
Справочник по конфигурации, generated API и поведению `@gromlab/svg-sprites`. Пошаговую установку смотрите в руководстве для вашего стека:
- [Bare standalone](../guides/standalone.md)
@@ -24,7 +26,7 @@
Для генерации не нужна dependency проекта. Запускайте CLI через `npx`:
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites path/to/svg-sprite.config.ts
npx --yes @gromlab/svg-sprites path/to/svg-sprite.config.json
```
Устанавливайте пакет как development dependency, только если проекту нужны
@@ -36,7 +38,7 @@ npm install --save-dev @gromlab/svg-sprites
## CLI и режимы генерации
CLI принимает ровно один путь: явно выбранный config-файл либо каталог для config-less генерации:
Для генерации CLI принимает ровно один путь: явно выбранный config-файл либо каталог для config-less генерации:
```text
svg-sprites [options] <config-file-or-directory>
@@ -54,11 +56,11 @@ svg-sprites [options] <config-file-or-directory>
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
Config-файл может иметь любое имя и расширение `.ts`, `.js` или `.json`. CLI не ищет конфиг по соглашению: файл нужно передать явно. В руководствах используется рекомендуемое имя `svg-sprite.config.ts`.
Config-файл может иметь любое имя и расширение `.ts`, `.js` или `.json`. CLI не ищет конфиг по соглашению: файл нужно передать явно. В руководствах используется рекомендуемое имя `svg-sprite.config.json`.
Если передан каталог, все настройки берутся из CLI. Если передан config-файл, CLI-параметры перекрывают значения файла. Общий порядок: `defaults → config → CLI`.
Доступны `--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.
`--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.
В CLI заключайте glob-паттерны в одинарные кавычки, чтобы shell не раскрыл их до запуска генератора:
@@ -96,7 +98,7 @@ export default defineSpriteConfig({
| Опция | Тип | По умолчанию | Назначение |
|---|---|---|---|
| `mode` | `SpriteMode` | Нет | Режим генерации; можно передать через CLI/API |
| `name` | `string` | Выводится из каталога | Имя спрайта, компонента и публичных типов |
| `name` | `string` | Выводится из каталога | Имя спрайта; в modes с компонентом также задаёт имя компонента и публичных типов |
| `description` | `string` | Нет | Описание для типов и debug manifest |
| `input` | `string \| string[]` | `./icons` | Папки, SVG-файлы и glob-паттерны относительно папки конфига |
| `transform` | `TransformOptions` | Все включены | Настройки подготовки SVG |
@@ -111,7 +113,7 @@ app → AppIcon
file-manager → FileManagerIcon
```
Если `name` не задано, генератор выводит его из каталога. Для каталога с именем `svg-sprite` или `svg-sprites` используется имя родительского каталога.
Если `name` не задано, генератор преобразует имя каталога в kebab-case. Для каталога с именем `svg-sprite` или `svg-sprites` используется имя родительского каталога.
### Источники иконок
@@ -141,7 +143,7 @@ file-manager → FileManagerIcon
```text
app-icons/
├── .gitignore
├── svg-sprite.config.ts
├── svg-sprite.config.json
├── index.ts # необязательный пользовательский barrel
└── .svg-sprite/
├── index.js
@@ -183,10 +185,10 @@ runtime asset и deployment-neutral manifest data:
generated Web Component без внешних runtime-зависимостей. Bare `standalone`
намеренно не создаёт JavaScript-компонент.
Генератор перезаписывает и удаляет только файлы со своим marker. Если в managed-пути находится пользовательский файл, генерация завершается ошибкой. Корневой `index.ts` генератору не принадлежит; при необходимости создайте пользовательский barrel:
`.svg-sprite` полностью управляется генератором и при каждой генерации заменяется целиком. Любые добавленные в него файлы будут удалены. Пользовательские файлы размещайте рядом, например в корневом `index.ts`:
```ts
export * from './.svg-sprite'
export * from './.svg-sprite/index.js'
```
## Standalone Web Component и TypeScript
@@ -307,7 +309,7 @@ folder open.svg → icon="folder open" → id="icon-<stable-hash>"
## Множественные спрайты
Каждый каталог с конфигом создаёт независимый компонент, типы, manifest и SVG asset:
Каждый каталог с конфигом создаёт независимый mode-specific контракт. React и Next.js создают React-компонент и типы, `standalone@vite` и `standalone@webpack` — Web Component и типы, а bare `standalone` — SVG и JSON manifest:
```text
app-icons → AppIcon → общие иконки
@@ -353,7 +355,7 @@ Static HTML после публикации `.svg-sprite/sprite.svg` прило
</svg>
```
Standalone Vite/Webpack предоставляет generated `getIconsIconHref()` и mapping
Standalone Vite/Webpack предоставляет generated `getAppIconHref()` и mapping
внутренних IDs. Не конструируйте fragment из небезопасного имени файла вручную.
Vite:
@@ -602,7 +604,7 @@ Viewer показывает группы, поиск, `viewBox`, CSS-перем
```json
{
"scripts": {
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/app-icons/svg-sprite.config.ts",
"sprites": "npx --yes @gromlab/svg-sprites src/ui/app-icons/svg-sprite.config.ts",
"predev": "npm run sprites",
"prebuild": "npm run sprites",
"pretypecheck": "npm run sprites"
@@ -610,22 +612,22 @@ Viewer показывает группы, поиск, `viewBox`, CSS-перем
}
```
CI должен выполнять generation script до сборки или проверки типов. Для воспроизводимости замените `latest` на точную версию. Локальная установка package не нужна, если CI не использует Viewer, package-типы config или программный API.
CI должен выполнять generation script до сборки или проверки типов. Локальная установка package не нужна, если CI не использует Viewer, package-типы config или программный API.
Bare `standalone` не создаёт и не изменяет `.gitignore`: приложение само решает, коммитить или игнорировать его `.svg-sprite/`. В остальных modes генератор не перезапишет пользовательский `.gitignore`. Он также откажется перезаписывать пользовательский файл внутри `.svg-sprite`. Корневой `index.ts` остаётся пользовательским и может переэкспортировать generated API.
Bare `standalone` не создаёт `.gitignore` и сохраняет пользовательский файл. Если после другого mode остался управляемый `.gitignore`, bare mode удалит его. В остальных modes генератор откажется перезаписать пользовательский `.gitignore` без generated marker. Корневой `index.ts` остаётся пользовательским и может переэкспортировать generated API.
## Диагностика
- Нет `.svg-sprite/index.js`: запустите generation script до импорта generated-модуля.
- Для всех modes, кроме bare `standalone`: если нет `.svg-sprite/index.js`, запустите generation script до импорта generated-модуля.
- Не найден источник: передайте существующий config-файл или каталог sprite-модуля.
- Не указан mode: добавьте `mode` в config либо передайте `--mode`.
- Иконка отсутствует в типе: проверьте `input`, расширение `.svg`, glob-исключения и необходимость `**/*.svg` для вложенных папок.
- Конфликт имени: два разных SVG имеют одинаковый basename; переименуйте один файл.
- `Refusing to overwrite a user file`: в managed-пути находится файл без generated marker.
- `Refusing to overwrite a user file`: в корне sprite-модуля находится пользовательский `.gitignore`, который генератор не может заменить.
- Иконка не меняет цвет: используйте `<svg><use>` или generated-компонент и проверьте `replaceColors`.
- Webpack выдаёт неверный URL: проверьте Asset Modules, `output.publicPath` и SVG loaders.
- Static sprite возвращает 404: проверьте post-generation copy или server alias и не передавайте filesystem `spritePath` в HTML.
- Viewer не видит спрайт: проверьте путь к `.svg-sprite/svg-sprite.manifest.js` и выполните генерацию до запуска приложения.
- Viewer не видит спрайт: для bundler modes проверьте путь к `.svg-sprite/svg-sprite.manifest.js`; для bare `standalone` — URL опубликованных `svg-sprite.manifest.json` и `sprite.svg`. Выполните генерацию до запуска приложения.
- Build и mode не совпадают: используйте target, соответствующий фактическому сборщику.
Для собственного orchestration и низкоуровневой компиляции смотрите [Программный API](programmatic-api.md).

View File

@@ -1,31 +1,25 @@
# AI skills
Исходники обязательного контекста английского и русского skills находятся в `skills/svg-sprites/src/{en,ru}/`. Канонические exact-mode guides находятся в `docs/{en,ru}/guides/` и копируются в соответствующий skill без изменения. Готовые переносимые артефакты генерируются в `skills/artifacts/`, игнорируются Git и упаковываются в ZIP во время release workflow.
Исходники обязательного контекста английского и русского skills находятся в `skills/svg-sprites/src/{en,ru}/`. Готовые переносимые артефакты генерируются в `skills/artifacts/`, игнорируются Git и упаковываются в ZIP во время release workflow.
Обе языковые версии имеют одинаковую структуру:
Русский skill хранит весь обязательный контекст в одном файле:
```text
src/<language>/
src/ru/
├── SKILL.md
├── core/
│ ├── 00-package-overview.md
│ ├── 10-mode-selection.md
│ ├── 20-project-inspection.md
│ ├── 30-react-next-setup.md
│ ├── 40-generated-contract.md
│ ├── 50-usage-and-colors.md
│ ├── 60-verification.md
│ └── 70-diagnostics.md
└── references/
├── programmatic-api.md
└── complex-svg.md
```
`core/` содержит обязательные знания, раскрываемые прямо в итоговый `SKILL.md`. Локальный `references/` содержит только agent-specific материалы. Девять файлов из `docs/<language>/guides/` копируются в `references/guides/`; английский artifact получает только английские guides, русский только русские. Второй набор mode guides и каталог `references/upstream/` не создаются.
`src/ru/SKILL.md` содержит знания о пакете и рабочий процесс агента. Exact-mode настройка берётся из canonical guides, а не дублируется отдельными source-фрагментами.
Русский artifact дополнительно получает без изменений `README_RU.md` и содержательную пользовательскую документацию из `docs/ru/`. Локальный редакторский `guides/AGENTS.md`, а также навигационные `guides/README.md` и `reference/README.md` не копируются. Файлы находятся в `references/README_RU.md` и `references/docs/ru/`. Agent-specific `complex-svg.md` остаётся отдельным reference.
Английский source пока сохраняет составную структуру с `core/`, а artifact — английские exact-mode guides и локальные `programmatic-api.md`/`complex-svg.md`. Его перевод на единый `SKILL.md` и полную canonical-документацию выполняется отдельно.
## Композиция Markdown
В любой собираемый документ можно включать фрагменты:
Сборщик сохраняет поддержку Markdown includes для английского skill и будущих документов:
```md
<!-- include: ./core/10-mode-selection.md -->

View File

@@ -137,7 +137,13 @@ function expandCopies(config) {
assertSafeRelativePath(entry.toDirectory)
const sourceDirectory = path.resolve(skillDir, entry.fromDirectory)
const extensions = entry.extensions ?? []
for (const relativePath of listDirectoryFiles(sourceDirectory, extensions)) {
const sourceFiles = listDirectoryFiles(sourceDirectory, extensions)
const excluded = new Set((entry.exclude ?? []).map((relativePath) => {
assertSafeRelativePath(relativePath)
return relativePath.replaceAll('\\', '/')
}))
for (const relativePath of sourceFiles) {
if (excluded.has(relativePath)) continue
copies.push({
from: path.join(sourceDirectory, relativePath),
to: path.posix.join(entry.toDirectory, relativePath),

View File

@@ -1,7 +1,12 @@
const agentReferences = [
const agentReferences = {
en: [
'programmatic-api.md',
'complex-svg.md',
]
],
ru: [
'complex-svg.md',
],
}
const guideFiles = [
'standalone.md',
@@ -18,7 +23,7 @@ const guideFiles = [
function documents(language) {
return [
{ entry: `src/${language}/SKILL.md`, to: 'SKILL.md', skill: true },
...agentReferences.map((file) => ({
...agentReferences[language].map((file) => ({
entry: `src/${language}/references/${file}`,
to: `references/${file}`,
})),
@@ -32,6 +37,20 @@ function guides(language) {
}))
}
const russianDocumentation = [
{ from: '../../README_RU.md', to: 'references/README_RU.md' },
{
fromDirectory: '../../docs/ru',
toDirectory: 'references/docs/ru',
extensions: ['.md'],
exclude: [
'guides/AGENTS.md',
'guides/README.md',
'reference/README.md',
],
},
]
export default [
{
name: 'svg-sprites',
@@ -43,10 +62,10 @@ export default [
},
{
name: 'svg-sprites-ru',
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.ts, defineSpriteConfig, generateSprite, standalone, standalone@vite, standalone@webpack, react@vite, react@webpack, next@app, next@pages, SpriteConfig.input, --input, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.json, svg-sprite.config.ts, defineSpriteConfig, generateSprite, standalone, standalone@vite, standalone@webpack, react@vite, react@webpack, next@app, next@pages, SpriteConfig.input, --input, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
output: '../artifacts/svg-sprites-ru',
maxSkillBytes: 48_000,
documents: documents('ru'),
copy: guides('ru'),
copy: russianDocumentation,
},
]

View File

@@ -1,19 +1,282 @@
# @gromlab/svg-sprites
<!-- include: ./core/00-package-overview.md -->
<!-- include: ./core/10-mode-selection.md -->
<!-- include: ./core/20-project-inspection.md -->
<!-- include: ./core/30-react-next-setup.md -->
<!-- include: ./core/40-generated-contract.md -->
<!-- include: ./core/50-usage-and-colors.md -->
<!-- include: ./core/60-verification.md -->
<!-- include: ./core/70-diagnostics.md -->
## Что делает пакет
## Справочники по необходимости
`@gromlab/svg-sprites` — CLI-генератор SVG-спрайтов для пользовательских SVG-файлов. Пакет не содержит собственного набора иконок: он собирает SVG проекта во внешний sprite asset, создаёт нативный типизированный Web Component для standalone bundler modes и React-компонент для React/Next.js.
- Для статической публикации открой [bare standalone](./references/guides/standalone.md). Для vanilla-приложений со сборщиком открой [standalone + Vite](./references/guides/standalone-vite.md) или [standalone + Webpack](./references/guides/standalone-webpack.md).
- Для React открой exact guide для [Vite](./references/guides/react-vite.md) или [Webpack](./references/guides/react-webpack.md).
- Для Next.js App Router открой exact guide для [Turbopack](./references/guides/next-app-turbopack.md) или [Webpack](./references/guides/next-app-webpack.md).
- Для Next.js Pages Router открой exact guide для [Turbopack](./references/guides/next-pages-turbopack.md) или [Webpack](./references/guides/next-pages-webpack.md).
- Для вызова генератора из Node.js открой [программный API](./references/programmatic-api.md).
- Для gradients, filters, `url(#...)`, нестандартных цветов и проблем с `viewBox` открой [сложные SVG](./references/complex-svg.md).
Пакет рассчитан на несколько независимых спрайтов в одном проекте. Каждый явно выбранный config-файл или config-less каталог описывает один спрайт и получает собственные:
- SVG asset;
- mode-specific manifest data;
- для bundler modes — типы имён и production entry `.svg-sprite/index.js`;
- для `standalone@vite`/`standalone@webpack` — нативный Web Component с явной функцией регистрации;
- только для React/Next.js — React-компонент;
- для bare `standalone` — deployment-neutral JSON manifest без публичного URL.
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Это примеры API отдельных спрайтов, а не фиксированные экспорты пакета.
Generated production runtime и declarations не импортируют `@gromlab/svg-sprites`. Генерация через `npx --yes @gromlab/svg-sprites <path-to-config>` не добавляет package в проект. Устанавливай его как development dependency только для Viewer, package-типов config или программного API.
## Выбор режима
Выбери ровно один поддерживаемый mode key:
| Проект | Mode key |
|---|---|
| Static HTML / собственная публикация | `standalone` |
| Standalone + Vite | `standalone@vite` |
| Standalone + Webpack 5 | `standalone@webpack` |
| React + Vite | `react@vite` |
| React + Webpack 5 | `react@webpack` |
| Next.js App Router + Turbopack | `next@app/turbopack` |
| Next.js App Router + Webpack 5 | `next@app/webpack` |
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
Mode задаётся в config, CLI или программном API. Порядок применения: `defaults → config → CLI/API overrides`. После объединения mode обязателен.
`name` необязателен. Если он не задан, генератор преобразует имя каталога sprite-модуля в kebab-case; для каталогов `svg-sprite` и `svg-sprites` используется имя родительского каталога. Явное `name` должно уже быть записано в kebab-case и начинаться с латинской буквы.
CLI принимает ровно один путь. Путь к файлу `.ts`, `.js` или `.json` загружает именно этот конфиг независимо от имени. Путь к каталогу включает config-less генерацию, и настройки передаются флагами CLI.
```json
{
"scripts": {
"sprite:<name>": "npx --yes @gromlab/svg-sprites <path-to-config>",
"sprite:<name>:cli": "npx --yes @gromlab/svg-sprites --mode <mode-key> <sprite-directory>"
}
}
```
Генерация через `npx` не добавляет package в проект. Не используй неполные `react`, `next@app`, `next@pages`, `standalone@` или удалённый `legacy`. Bare `standalone` выбирай только когда приложение само публикует SVG; для Vite/Webpack используй соответствующий полный key. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.
## Инспекция проекта
До изменений установи фактический контракт проекта:
1. Прочитай корневой `package.json`, lock-файл и workspace-конфигурацию; определи framework, bundler и существующие команды.
2. Найди config-файлы, команды `svg-sprites` и импорты generated-компонентов. Имя конфига произвольное; ориентируйся на переданный CLI путь и поля объекта.
3. Для React определи Vite или Webpack 5 по scripts и конфигу. Для Next.js отдельно определи App/Pages Router и сборщик реальных `dev`/`build` команд.
4. Проверь существующие `predev`, `prebuild`, `pretypecheck` и агрегирующие scripts. Не перезаписывай их.
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
Все input-пути считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога. Проверяй `input` как единый контракт:
- `input?: string | string[]` по умолчанию равен `./icons`;
- каждая строка задаёт папку, точный SVG-файл или glob;
- папка сканируется плоско; вложенные файлы включаются только явным recursive glob, например `./icons/**/*.svg`;
- массив объединяет positive-источники, а элемент с префиксом `!` исключает свои совпадения из общего набора;
- каждый positive-источник должен разрешаться хотя бы в один SVG, поэтому отсутствующая или пустая папка, glob без совпадений, отсутствующий файл или точный путь не к SVG являются ошибкой;
- разрешённые файлы дедуплицируются и детерминированно сортируются;
- разные файлы с одинаковым basename конфликтуют, даже если получены из разных источников.
Не копируй общий SVG в несколько папок: добавь его точный путь или подходящий glob в `input` каждого нужного спрайта. Используй `**/*.svg` только для намеренного рекурсивного включения.
## Настройка интеграции
Не воспроизводи настройку mode по памяти. После инспекции проекта выбери один exact mode и открой соответствующий файл из `references/docs/ru/guides/`. Используй guide как базовый рабочий контракт, затем адаптируй его к существующей структуре проекта.
Работай в таком порядке:
1. Определи каталог исходных SVG и каталог одного sprite-модуля. Один config создаёт один независимый спрайт; для нескольких наборов нужны отдельные config-файлы и уникальные `name`.
2. Сверь framework, router и bundler с exact mode. Для Next.js проверяй реальные `dev` и `build` scripts, а не только наличие `next.config.*`.
3. Предпочитай JSON-конфиг, если проекту не нужны package-типы config. TypeScript-конфиг также загружается через CLI, но установка package нужна, когда он импортирует `defineSpriteConfig` или типы.
4. Разрешай все `input` относительно каталога config-файла. Не меняй структуру SVG без необходимости: используй путь к папке, точный файл, glob или массив этих источников.
5. Добавь sprite-команду с явным путём к config. Сохрани существующие `dev`, `build`, `typecheck` и lifecycle hooks; встрой генерацию до первого процесса, импортирующего `.svg-sprite`.
6. Не запускай одну генерацию дважды через одновременный `predev` и `npm run sprites && ...`. Для нескольких спрайтов создай отдельные команды и один агрегирующий script.
7. Если приложение импортирует каталог sprite-модуля, создай пользовательский `index.ts` рядом с `.svg-sprite`; не помещай пользовательские файлы внутрь generated-каталога.
8. Выполни первую генерацию до typecheck или запуска приложения, затем проверь mode-specific output и фактический импорт компонента.
Не добавляй Viewer автоматически. Подключай его только по запросу пользователя или когда нужна визуальная проверка набора, цветов либо сложных SVG. Способ изоляции Viewer от production бери из exact guide: Vite, Webpack, App Router и Pages Router используют разные границы.
Не копируй snippets между exact modes даже при похожем API. Различаются asset URL, generated-файлы, CSS handling, router boundary и способ подключения debug-инструментов.
## Контракт generated-каталога
После генерации React/Next-каталог имеет следующий вид:
```text
svg-sprite/
├── icons/ # пользовательские исходники
├── svg-sprite.config.json # рекомендуемое имя конфига
├── index.ts # необязательный пользовательский barrel
├── .gitignore # управляет генератор
└── .svg-sprite/
├── index.js
├── index.d.ts
├── icon-data.js
├── icon-data.d.ts
├── sprite.svg
├── svg-sprite.manifest.js
├── svg-sprite.manifest.d.ts
└── react/
├── react-component.js
├── react-component.d.ts
└── react-component.module.css
```
Standalone не создаёт `react/`. Bare `standalone` генерирует `sprite.svg` и `svg-sprite.manifest.json`; `standalone@vite`/`standalone@webpack` дополнительно генерируют `index.*`, `icon-data.*` и resolved manifest. Их `index.*` также содержит нативный generated Web Component; bare `standalone` не получает JS runtime и не создаёт `.gitignore`.
Редактируй исходные SVG, config-файл и пользовательский `index.ts`. Не изменяй вручную содержимое `.svg-sprite`: повторная генерация его перезапишет. Во всех modes, кроме bare `standalone`, generated `.gitignore` также находится под управлением генератора. Для импорта из корня sprite-модуля создай barrel:
```ts
export * from './.svg-sprite/index.js'
```
Генератор полностью владеет каталогом `.svg-sprite` и заменяет его при каждом запуске. Никогда не помещай туда пользовательские файлы. Генератор также владеет `.gitignore`, когда выбранный mode его создаёт. Bare `standalone` сохраняет пользовательский `.gitignore`, но удаляет управляемый `.gitignore`, оставшийся после другого mode. Generated-пути не должны содержать symlink.
В React/Next modes внутренний `index.js` экспортирует компонент из `react/react-component.js` и readonly-массив имён, а `index.d.ts` добавляет props/style-типы и union имени. Standalone bundler modes экспортируют Web Component helpers и типы без `react/`; bare `standalone` не создаёт facade. Manifest declarations bundler modes объявляют типы локально и не импортируют generator package. Manifest содержит mode, target, список и метаданные иконок для debug-инструментов; bundler manifest также содержит URL и не импортируется production-компонентом.
В bundler modes спрайт остаётся отдельным asset, а SVG path-данные не встраиваются в JavaScript. Content hash зависит от настроек сборщика. Bare `standalone` создаёт файл с фиксированным именем, а приложение само определяет его публичное имя и версионирование:
- `react@vite` генерирует статический импорт `sprite.svg?no-inline`, запрещающий Vite inline;
- `standalone@vite` использует тот же Vite asset-механизм и экспортирует href helper и нативный Web Component без React;
- `standalone@webpack` использует Webpack Asset Modules и экспортирует такой же mode-local Web Component без React;
- React Webpack 5 и все Next modes получают asset через `new URL(..., import.meta.url).href`, который должен обработать соответствующий сборщик;
- кастомный Webpack SVG loader не должен перехватывать generated `sprite.svg`;
- в Next mode generated-компонент не содержит `'use client'` и работает в Server Components, SSR и SSG; не добавляй клиентскую границу только ради иконки;
- команда сборки Next и mode key должны совпадать: Turbopack с `.../turbopack`, Webpack с `.../webpack`.
Для bundler modes не перемещай generated sprite в `public` и не переписывай URL вручную. Для bare `standalone` не перемещай managed original: приложение может явно копировать его в deploy output и само отвечает за публичный URL и очистку копии. При смене mode перегенерируй спрайт с новым полным key.
## Использование, доступность и цвета
Имя компонента зависит от `name` конкретного спрайта. В `standalone@vite` и `standalone@webpack` значение `name: 'file-manager'` создаёт tag `<file-manager-icon>` и функцию `defineFileManagerIconElement()`:
```ts
import { defineFileManagerIconElement } from './svg-sprite'
defineFileManagerIconElement()
```
```html
<file-manager-icon icon="folder" aria-hidden="true"></file-manager-icon>
```
Нативный элемент не имеет runtime-зависимостей, сам выбирает generated ID и `viewBox`, получает URL через bundler и рендерит `<svg><use>` в Shadow DOM. Его property `icon` типизирован точным union имён, но строковые HTML attributes проверяются только в runtime. Размер по умолчанию равен `1em × 1em`; меняй его через CSS на host. Bare `standalone` Web Component не генерирует.
В React/Next.js тот же `name: 'file-manager'` создаёт React-компонент `FileManagerIcon`. Для `name: 'navigation'` используй сгенерированный `NavigationIcon`.
Импортируй компонент из корня соответствующего каталога спрайта. `width` и `height` не обязательны: размером можно управлять обычным CSS-классом.
```tsx
import { FileManagerIcon } from './svg-sprite'
export const OpenButton = () => (
<button type="button">
<FileManagerIcon icon="folder" className="icon" aria-hidden="true" />
<span>Открыть</span>
</button>
)
```
```css
.icon {
width: 24px;
height: 24px;
color: #4b5563;
}
```
`icon` принимает точные имена исходных файлов без `.svg`; неизвестное имя является ошибкой TypeScript. Для небезопасных SVG ID имён генератор хранит публичное имя, но создаёт внутренний стабильный hash ID, поэтому не собирай fragment URL из имени вручную.
По умолчанию компонент рендерит `<svg>` и принимает стандартные SVG attributes: необязательные `width`/`height`, `className`, `style`, `role`, `aria-*` и обработчики. С `wrapped={true}` корнем становится `<span>`, props относятся к span, а внутренний SVG занимает размер wrapper.
Generated-компонент не выбирает семантику за приложение и не добавляет `title`. Для декоративной иконки передай `aria-hidden="true"`; для самостоятельной смысловой иконки передай `role="img"` и доступное имя через `aria-label`. Не дублируй имя, если соседний текст уже озвучивает действие. Интерактивность размещай на `button` или `a`, а не на самой иконке.
Трансформации `removeSize`, `replaceColors` и `addTransition` включены по умолчанию. Для монохромной иконки единственный цвет получает fallback `currentColor`, поэтому управляй CSS-свойством `color`. Для многоцветной передавай типизированные custom properties:
```tsx
<FileManagerIcon
icon="folder"
style={{
'--icon-color-1': '#4b5563',
'--icon-color-2': '#14b8a6',
}}
/>
```
Автозамена рассчитана на `fill`/`stroke` attributes и inline `style`. Значения `none`, `transparent`, `inherit`, `unset`, `initial` не заменяются. CSS-классы и внешние stylesheets, gradients, patterns, filters и `url(#...)` проверяй на реальном результате. Переменные страницы работают через `<svg><use>`, но не проникают во внешний документ при `<img>` или `background-image`; CSS mask оставляет только одноцветный силуэт.
`SpriteViewer` необязателен. Установи `@gromlab/svg-sprites` как development dependency, только если проекту нужен Viewer. Он принимает manifests или статически обнаружимые loaders, показывает поиск, темы, цвета и примеры, но production-компоненты от него не зависят.
Перед подключением Viewer открой exact guide. Vite использует отдельную HTML entry, обычный Webpack — development-only entry, Next.js — debug route, а App Router дополнительно требует отдельную Client Component boundary. Не переноси способ подключения между modes.
## Проверка результата
После изменения конфига или SVG выполни обязательные проверки:
1. Запусти точную sprite-команду. Процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `.svg-sprite`.
2. Проверь output выбранного exact mode:
- bare `standalone` создаёт `sprite.svg` и `svg-sprite.manifest.json`;
- `standalone@vite` и `standalone@webpack` дополнительно создают `index.*`, `icon-data.*` и JS manifest, но не каталог `react/`;
- React и Next.js modes также создают `react/react-component.js`, declaration и CSS Module.
3. Для modes с public facade проверь `.svg-sprite/index.js`, соседний `index.d.ts`, список имён и фактический импорт через пользовательский barrel.
4. Проверь manifest: mode и target должны соответствовать выбранному adapter, а список иконок — исходным SVG. В bundler modes URL должен формироваться mode-specific способом; bare JSON manifest намеренно не содержит публичного `spriteUrl`.
5. Запусти существующий typecheck проекта, если mode создаёт типы или изменился пользовательский TypeScript-код.
6. Запусти минимальную команду приложения, затронутую изменением: `dev`, build или специализированную проверку проекта.
Не запускай полную production-сборку только ради проверки нового имени иконки. Она нужна, если менялся bundler target, router, Webpack loader, asset URL, deployment path или диагностируется production-only ошибка.
Визуальную проверку, Network и accessibility tree выполняй только при наличии запущенного приложения и браузерных инструментов. Если таких инструментов нет, не утверждай, что цвета, темы, доступность или HTTP-ответ asset проверены; явно укажи непроверенную часть.
Viewer используй для сложных цветов, transforms и массовой визуальной проверки. Не добавляй debug route ради обычной генерации одного спрайта.
## Диагностика
Сопоставь симптом с проверкой и исправляй первопричину:
| Симптом | Вероятная причина | Действие |
|---|---|---|
| `Missing sprite config file or module directory` | Не передан позиционный путь | Передай один config-файл либо каталог для config-less запуска. |
| `Expected one config file or module directory` | Передано несколько путей | Создай отдельную команду на каждый спрайт и объедини scripts. |
| `Sprite mode is required` | Mode отсутствует и в config, и в CLI | Добавь `mode` в объект или передай полный `--mode`. |
| `Unsupported sprite config extension` | Передан файл не `.ts`, `.js` или `.json` | Используй поддерживаемый формат config-файла. |
| Positive input-источник не нашёл SVG | Папка отсутствует или пуста, glob не совпал либо точный путь отсутствует или ведёт не к SVG | Разреши источник от каталога конфига и исправь `input`; каждый positive-элемент должен дать хотя бы один SVG. |
| Иконки из подпапки не появились | От папки ожидалось рекурсивное сканирование | Используй явный glob, например `./icons/**/*.svg`; папки сканируются плоско. |
| Исключённая иконка всё ещё присутствует | У исключения нет префикса `!`, оно находится не в массиве `input` или считается не от того каталога | Добавь совпадающий `!`-элемент и считай его от каталога конфига. |
| CLI выбрал не все источники | Несколько источников поместили в одно значение `--input` или пропустили option | Повтори `--input <path-or-glob>` отдельно для каждого источника или исключения. |
| Конфликт имени иконки или SVG ID | Два разных файла имеют одинаковый basename либо hash-ID столкнулся с именем | Переименуй один исходный SVG; не выбирай файл неявно. |
| `Refusing to overwrite a user file` | В корне sprite-модуля уже есть пользовательский `.gitignore`, который mode должен создать | Не перезаписывай файл: выбери другой sprite-каталог или согласуй перенос существующего `.gitignore`. |
| Нет `.svg-sprite/index.js` или имя отсутствует в autocomplete | Для bare `standalone` это ожидаемо; в остальных modes генерация не запускалась, barrel неверен либо type server держит старый модуль | Сверь exact mode, запусти sprite-команду, проверь `export * from './.svg-sprite/index.js'`, затем typecheck; при необходимости перезапусти TypeScript server. |
| SVG не загружается или URL неверен | Mode не совпадает со сборщиком, неверен Webpack `publicPath` либо кастомный loader перехватил asset | Сверь mode и build-команду, проверь Asset Modules/`publicPath`, исключи generated SVG из несовместимого loader. |
| Next build расходится между SSR и браузером | Модуль сгенерирован для другого bundler/router или URL переписан вручную | Верни generated `new URL(...)`, выбери точный Next mode и перегенерируй. |
| `color` не меняет многоцветную иконку | У иконки несколько переменных или она показана через `<img>`/CSS background | Используй `<FileManagerIcon>`/`<svg><use>` и нужные `--icon-color-N`. |
| Gradient/filter выглядит неверно | Автозамена цветов не гарантирует сложные paint servers | Изучи generated SVG; при необходимости отключи `replaceColors` для спрайта или упрости источник. |
| Viewer пуст | Manifest не создан, loader не обнаружен сборщиком или неверна Client Component boundary | Сначала сгенерируй спрайт, затем сверь manifest import и способ подключения с exact guide; в App Router оставь `'use client'` только в компоненте Viewer. |
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к config-файлу или каталогу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и управляемый `.gitignore`.
## Карта reference-документации
References являются частью собранного skill. Открывай только документы, относящиеся к текущей задаче, но перед изменением интеграции exact-mode guide обязателен.
### Обзор
- [README пакета](./references/README_RU.md) — возможности, основной React/Next.js сценарий и ссылки на документацию.
### Конфигурация
- [Конфигурация](./references/docs/ru/configuration.md) — JSON, JavaScript, TypeScript, поля config, `input` и запуск CLI.
### Exact-mode guides
- [`standalone`](./references/docs/ru/guides/standalone.md) — static HTML и собственная публикация SVG.
- [`standalone@vite`](./references/docs/ru/guides/standalone-vite.md) — vanilla-приложение с Vite и Web Component.
- [`standalone@webpack`](./references/docs/ru/guides/standalone-webpack.md) — vanilla-приложение с Webpack 5 и Web Component.
- [`react@vite`](./references/docs/ru/guides/react-vite.md) — React с Vite.
- [`react@webpack`](./references/docs/ru/guides/react-webpack.md) — React с Webpack 5.
- [`next@app/turbopack`](./references/docs/ru/guides/next-app-turbopack.md) — Next.js App Router с Turbopack.
- [`next@app/webpack`](./references/docs/ru/guides/next-app-webpack.md) — Next.js App Router с Webpack.
- [`next@pages/turbopack`](./references/docs/ru/guides/next-pages-turbopack.md) — Next.js Pages Router с Turbopack.
- [`next@pages/webpack`](./references/docs/ru/guides/next-pages-webpack.md) — Next.js Pages Router с Webpack.
### Технические справочники
- [Технический справочник](./references/docs/ru/reference/technical.md) — requirements, CLI, naming, generated API, assets, transforms, цвета, Viewer, Git, CI и диагностика.
- [Программный API](./references/docs/ru/reference/programmatic-api.md) — `generateSprite`, overrides, config API, compiler и Viewer runtime.
### Agent-specific reference
- [Сложные SVG](./references/complex-svg.md) — gradients, patterns, filters, masks, `url(#...)`, `viewBox`, fragment IDs и визуальная диагностика.

View File

@@ -1,16 +0,0 @@
## Что делает пакет
`@gromlab/svg-sprites` — CLI-генератор SVG-спрайтов для пользовательских SVG-файлов. Пакет не содержит собственного набора иконок: он собирает SVG проекта во внешний sprite asset, создаёт нативный типизированный Web Component для standalone bundler modes и React-компонент для React/Next.js.
Пакет рассчитан на несколько независимых спрайтов в одном проекте. Каждый явно выбранный config-файл или config-less каталог описывает один спрайт и получает собственные:
- SVG asset;
- mode-specific manifest data;
- для bundler modes — типы имён и production entry `.svg-sprite/index.js`;
- для `standalone@vite`/`standalone@webpack` — нативный Web Component с явной функцией регистрации;
- только для React/Next.js — React-компонент;
- для bare `standalone` — deployment-neutral JSON manifest без публичного URL.
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Имена `FileManagerIcon` и `fileManagerIconNames` ниже являются примерами API одного из возможных спрайтов, а не фиксированными экспортами пакета.
Generated production runtime и declarations не импортируют `@gromlab/svg-sprites`. Генерация работает через `npx --package` с зафиксированной версией без добавления package в проект. Устанавливай его как development dependency только для Viewer, package-типов config или программного API.

View File

@@ -1,30 +0,0 @@
## Выбор режима
Выбери ровно один поддерживаемый mode key:
| Проект | Mode key |
|---|---|
| Static HTML / собственная публикация | `standalone` |
| Standalone + Vite | `standalone@vite` |
| Standalone + Webpack 5 | `standalone@webpack` |
| React + Vite | `react@vite` |
| React + Webpack 5 | `react@webpack` |
| Next.js App Router + Turbopack | `next@app/turbopack` |
| Next.js App Router + Webpack 5 | `next@app/webpack` |
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
Mode задаётся в config, CLI или программном API. Порядок применения: `defaults → config → CLI/API overrides`. После объединения mode обязателен.
CLI принимает ровно один путь. Путь к файлу `.ts`, `.js` или `.json` загружает именно этот конфиг независимо от имени. Путь к каталогу включает config-less генерацию, и настройки передаются флагами CLI.
```json
{
"scripts": {
"sprite:<name>": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites <path-to-config>",
"sprite:<name>:cli": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites --mode <mode-key> <sprite-directory>"
}
}
```
Генерация через `npx` не добавляет package в проект. В CI укажи точную версию вместо `latest`. Не используй неполные `react`, `next@app`, `next@pages`, `standalone@` или удалённый `legacy`. Bare `standalone` выбирай только когда приложение само публикует SVG; для Vite/Webpack используй соответствующий полный key. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.

View File

@@ -1,22 +0,0 @@
## Инспекция проекта
До изменений установи фактический контракт проекта:
1. Прочитай корневой `package.json`, lock-файл и workspace-конфигурацию; определи framework, bundler и существующие команды.
2. Найди config-файлы, команды `svg-sprites` и импорты generated-компонентов. Имя конфига произвольное; ориентируйся на переданный CLI путь и поля объекта.
3. Для React определи Vite или Webpack 5 по scripts и конфигу. Для Next.js отдельно определи App/Pages Router и сборщик реальных `dev`/`build` команд.
4. Проверь существующие `predev`, `prebuild`, `pretypecheck` и агрегирующие scripts. Не перезаписывай их.
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
Все input-пути считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога. Проверяй `input` как единый контракт:
- `input?: string | string[]` по умолчанию равен `./icons`;
- каждая строка задаёт папку, точный SVG-файл или glob;
- папка сканируется плоско; вложенные файлы включаются только явным recursive glob, например `./icons/**/*.svg`;
- массив объединяет positive-источники, а элемент с префиксом `!` исключает свои совпадения из общего набора;
- каждый positive-источник должен разрешаться хотя бы в один SVG, поэтому отсутствующая или пустая папка, glob без совпадений, отсутствующий файл или точный путь не к SVG являются ошибкой;
- разрешённые файлы дедуплицируются и детерминированно сортируются;
- разные файлы с одинаковым basename конфликтуют, даже если получены из разных источников.
Не копируй общий SVG в несколько папок: добавь его точный путь или подходящий glob в `input` каждого нужного спрайта. Используй `**/*.svg` только для намеренного рекурсивного включения.

View File

@@ -1,63 +0,0 @@
## Настройка React или Next.js
Выбери целевой каталог для одного спрайта. Он может находиться рядом с feature, в общем каталоге иконок или в любом другом месте, принятом в проекте. Следующая структура является только примером:
```text
src/ui/file-manager/svg-sprite/
├── icons/
│ ├── check.svg
│ └── folder.svg
└── svg-sprite.config.ts
```
Один `svg-sprite.config.ts` создаёт один независимый спрайт. Для нескольких наборов выбери несколько каталогов и дай каждому уникальное `name`.
Генератор не нужно устанавливать в проект. Начни с plain config без package
import:
```ts
export default {
mode: 'react@vite',
name: 'file-manager',
description: 'Иконки файлового менеджера',
input: ['./icons', '../../shared/icons/close.svg'],
}
```
`input` принимает одну папку, точный SVG-файл или glob либо массив, объединяющий эти источники. Элемент массива с префиксом `!` исключает совпадения. Папки сканируются плоско; для рекурсии нужен явный glob `**/*.svg`. Если `input` не задан, используется `./icons`. Все пути считаются от каталога конфига, и каждый positive-источник должен найти хотя бы один SVG.
Контракт объекта одинаков для React и Next.js; отличается полный `mode`. Устанавливай package только для необязательного Viewer, программного API или package-типизации config. В exact guides также есть локальный copy-paste type для проектов без package.
`name` должен начинаться с латинской буквы и записываться в kebab-case; из примера `file-manager` будут созданы `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`. Другой спрайт получает собственные имена. Если `name` не задан, генератор выводит его из каталога.
Добавь отдельную команду с выбранным mode key и одним путём:
```json
{
"scripts": {
"sprite:file-manager": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
"sprites": "npm run sprite:file-manager"
}
}
```
Для Next.js укажи в config полный ключ, например `next@app/turbopack`. Для нескольких спрайтов добавь по команде `sprite:<name>` на каждый config-файл и последовательно вызови их из `sprites`.
Чтобы задать источники через CLI, повторяй `--input <path-or-glob>`; значения образуют тот же массивный контракт, включая исключения с `!`:
```bash
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts \
--input ./icons \
--input '../../shared/icons/**/*.svg' \
--input '!../../shared/icons/legacy-*.svg'
```
Generated-файлы в `.svg-sprite` по умолчанию исключаются из Git, поэтому запускай `sprites` до процессов, которым нужны компонент, типы или asset. Если проект импортирует корень sprite-модуля, создай пользовательский `index.ts` с `export * from './.svg-sprite'`. Generated declarations self-contained и не импортируют generator package.
Запускай генерацию либо через `predev`/`prebuild`/`pretypecheck`, либо явно внутри соответствующих команд. Не используй обе формы для одной команды, иначе генерация выполнится дважды. Сохраняй существующие команды и не создавай второй одноимённый JSON key.
Запусти первую генерацию вручную:
```bash
npm run sprites
```

View File

@@ -1,51 +0,0 @@
## Контракт generated-каталога
После генерации React/Next-каталог имеет следующий вид:
```text
svg-sprite/
├── icons/ # пользовательские исходники
├── svg-sprite.config.ts # рекомендуемое имя конфига
├── index.ts # необязательный пользовательский barrel
├── .gitignore # управляет генератор
└── .svg-sprite/
├── index.js
├── index.d.ts
├── icon-data.js
├── icon-data.d.ts
├── sprite.svg
├── svg-sprite.manifest.js
├── svg-sprite.manifest.d.ts
└── react/
├── react-component.js
├── react-component.d.ts
└── react-component.module.css
```
Standalone не создаёт `react/`. Bare `standalone` генерирует `sprite.svg` и
`svg-sprite.manifest.json`; `standalone@vite`/`standalone@webpack` дополнительно
генерируют `index.*`, `icon-data.*` и resolved manifest. Их `index.*` также
содержит нативный generated Web Component; bare `standalone` не получает JS runtime,
не создаёт и не изменяет `.gitignore`.
Редактируй исходные SVG, config-файл и пользовательский `index.ts`. Не изменяй вручную содержимое `.svg-sprite`: повторная генерация его перезапишет. Во всех modes, кроме bare `standalone`, generated `.gitignore` также находится под управлением генератора. Для импорта из корня sprite-модуля создай barrel:
```ts
export * from './.svg-sprite'
```
Генератор полностью владеет каталогом `.svg-sprite` и заменяет его при каждом запуске. Никогда не помещай туда пользовательские файлы. Генератор также владеет `.gitignore`, когда выбранный mode его создаёт; bare `standalone` оставляет существующий `.gitignore` без изменений. Generated-пути не должны содержать symlink.
Внутренний `index.js` экспортирует компонент из `react/react-component.js` и readonly-массив имён; соседний `index.d.ts` добавляет props/style-типы и union имени. Manifest declarations bundler modes объявляют типы локально и не импортируют generator package. Manifest содержит mode, URL, target, список и метаданные иконок для debug-инструментов и не импортируется production-компонентом.
Спрайт остаётся отдельным asset с content hash; SVG path-данные не встраиваются в JavaScript:
- `react@vite` генерирует статический импорт `sprite.svg?no-inline`, запрещающий Vite inline;
- `standalone@vite` использует тот же Vite asset-механизм и экспортирует href helper и нативный Web Component без React;
- `standalone@webpack` использует Webpack Asset Modules и экспортирует такой же mode-local Web Component без React;
- React Webpack 5 и все Next modes генерируют `new URL('./sprite.svg', import.meta.url).href`, который должен обработать Asset Modules соответствующего сборщика;
- кастомный Webpack SVG loader не должен перехватывать generated `sprite.svg`;
- в Next mode generated-компонент не содержит `'use client'` и работает в Server Components, SSR и SSG; не добавляй клиентскую границу только ради иконки;
- команда сборки Next и mode key должны совпадать: Turbopack с `.../turbopack`, Webpack с `.../webpack`.
Для bundler modes не перемещай generated sprite в `public` и не переписывай URL вручную. Для bare `standalone` не перемещай managed original: приложение может явно копировать его в deploy output и само отвечает за публичный URL и очистку копии. При смене mode перегенерируй спрайт с новым полным key.

View File

@@ -1,87 +0,0 @@
## Использование, доступность и цвета
Имя компонента зависит от `name` конкретного спрайта. В `standalone@vite` и `standalone@webpack` значение `name: 'file-manager'` создаёт tag `<file-manager-icon>` и функцию `defineFileManagerIconElement()`:
```ts
import { defineFileManagerIconElement } from './svg-sprite'
defineFileManagerIconElement()
```
```html
<file-manager-icon icon="folder" aria-hidden="true"></file-manager-icon>
```
Нативный элемент не имеет runtime-зависимостей, сам выбирает generated ID и `viewBox`, получает URL через bundler и рендерит `<svg><use>` в Shadow DOM. Его property `icon` типизирован точным union имён, но строковые HTML attributes проверяются только в runtime. Размер по умолчанию равен `1em × 1em`; меняй его через CSS на host. Bare `standalone` Web Component не генерирует.
В React/Next.js тот же `name: 'file-manager'` создаёт React-компонент `FileManagerIcon`. Для `name: 'navigation'` используй сгенерированный `NavigationIcon`.
Импортируй компонент из корня соответствующего каталога спрайта. `width` и `height` не обязательны: размером можно управлять обычным CSS-классом.
```tsx
import { FileManagerIcon } from './svg-sprite'
export const OpenButton = () => (
<button type="button">
<FileManagerIcon icon="folder" className="icon" aria-hidden="true" />
<span>Открыть</span>
</button>
)
```
```css
.icon {
width: 24px;
height: 24px;
color: #4b5563;
}
```
`icon` принимает точные имена исходных файлов без `.svg`; неизвестное имя является ошибкой TypeScript. Для небезопасных SVG ID имён генератор хранит публичное имя, но создаёт внутренний стабильный hash ID, поэтому не собирай fragment URL из имени вручную.
По умолчанию компонент рендерит `<svg>` и принимает стандартные SVG attributes: необязательные `width`/`height`, `className`, `style`, `role`, `aria-*` и обработчики. С `wrapped={true}` корнем становится `<span>`, props относятся к span, а внутренний SVG занимает размер wrapper. Это удобно, когда размер и цвета полностью задаются классом:
```tsx
<FileManagerIcon
icon="check"
wrapped
className="statusIcon"
aria-hidden="true"
/>
```
```css
.statusIcon {
width: 1.5rem;
height: 1.5rem;
color: currentColor;
--icon-color-1: #4b5563;
--icon-color-2: #14b8a6;
}
```
Generated-компонент не выбирает семантику за приложение и не добавляет `title`. Для декоративной иконки передай `aria-hidden="true"`; для самостоятельной смысловой иконки передай `role="img"` и доступное имя через `aria-label`. Не дублируй имя, если соседний текст уже озвучивает действие. Интерактивность размещай на `button` или `a`, а не на самой иконке.
Трансформации `removeSize`, `replaceColors` и `addTransition` включены по умолчанию. Для монохромной иконки единственный цвет получает fallback `currentColor`, поэтому управляй CSS-свойством `color`. Для многоцветной передавай типизированные custom properties:
```tsx
<FileManagerIcon
icon="folder"
wrapped
className="folderIcon"
style={{
'--icon-color-1': '#4b5563',
'--icon-color-2': '#14b8a6',
}}
/>
```
Автозамена рассчитана на `fill`/`stroke` attributes и inline `style`. Значения `none`, `transparent`, `inherit`, `unset`, `initial` не заменяются. CSS-классы и внешние stylesheets, gradients, patterns, filters и `url(#...)` проверяй на реальном результате. Переменные страницы работают через `<svg><use>`, но не проникают во внешний документ при `<img>` или `background-image`; CSS mask оставляет только одноцветный силуэт.
`SpriteViewer` необязателен. Установи `@gromlab/svg-sprites` как development dependency, только если проекту нужен Viewer, и подключай его из `@gromlab/svg-sprites/react` на debug-маршруте:
- в Vite передай результат строкового literal `import.meta.glob('/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js')`;
- в Webpack передай массив статических `() => import('.../.svg-sprite/svg-sprite.manifest.js')`;
- в Next.js используй такие же статические loaders, а для App Router помести Viewer в отдельный файл с `'use client'`.
Viewer принимает manifests/loaders, показывает поиск, темы, цвета и примеры, но production-компоненты от него не зависят.

View File

@@ -1,15 +0,0 @@
## Проверка результата
После изменения конфига или SVG выполни обязательные быстрые проверки:
1. Запусти точную sprite-команду, например `npm run sprite:file-manager`; процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `.svg-sprite`.
2. Проверь наличие `.svg-sprite/index.js`, `.svg-sprite/index.d.ts`, `sprite.svg`, пары `icon-data.js`/`.d.ts`, manifest `.js`/`.d.ts`, `react/react-component.js`, его `.d.ts` и CSS Module.
3. Убедись, что новая иконка присутствует в readonly-массиве имён и принимается prop `icon`.
4. Запусти существующую проверку типов проекта, например `npm run typecheck`.
5. Проверь в `.svg-sprite/svg-sprite.manifest.js`, что `target` совпадает с выбранным mode key; generated asset expression должен быть `?no-inline` для Vite и `new URL(...)` для Webpack/Next.
Не запускай полную production-сборку только ради проверки изменения списка иконок. Она нужна, если менялся bundler target, конфигурация asset pipeline, Next router/bundler, Webpack loader или диагностируется ошибка URL в runtime.
Визуальную проверку, Network и accessibility tree выполняй только при наличии запущенного приложения и браузерных инструментов. Если таких инструментов нет, не утверждай, что цвета, темы, доступность или HTTP-ответ asset проверены; явно укажи непроверенную часть.
`SpriteViewer` также необязателен. Используй его для сложных цветов, transforms и массовой визуальной проверки, но не добавляй debug route ради обычной генерации одного спрайта.

View File

@@ -1,24 +0,0 @@
## Диагностика
Сопоставь симптом с проверкой и исправляй первопричину:
| Симптом | Вероятная причина | Действие |
|---|---|---|
| `Missing sprite config file or module directory` | Не передан позиционный путь | Передай один config-файл либо каталог для config-less запуска. |
| `Expected one config file or module directory` | Передано несколько путей | Создай отдельную команду на каждый спрайт и объедини scripts. |
| `Sprite mode is required` | Mode отсутствует и в config, и в CLI | Добавь `mode` в объект или передай полный `--mode`. |
| `Unsupported sprite config extension` | Передан файл не `.ts`, `.js` или `.json` | Используй поддерживаемый формат config-файла. |
| Positive input-источник не нашёл SVG | Папка отсутствует или пуста, glob не совпал либо точный путь отсутствует или ведёт не к SVG | Разреши источник от каталога конфига и исправь `input`; каждый positive-элемент должен дать хотя бы один SVG. |
| Иконки из подпапки не появились | От папки ожидалось рекурсивное сканирование | Используй явный glob, например `./icons/**/*.svg`; папки сканируются плоско. |
| Исключённая иконка всё ещё присутствует | У исключения нет префикса `!`, оно находится не в массиве `input` или считается не от того каталога | Добавь совпадающий `!`-элемент и считай его от каталога конфига. |
| CLI выбрал не все источники | Несколько источников поместили в одно значение `--input` или пропустили option | Повтори `--input <path-or-glob>` отдельно для каждого источника или исключения. |
| Конфликт имени иконки или SVG ID | Два разных файла имеют одинаковый basename либо hash-ID столкнулся с именем | Переименуй один исходный SVG; не выбирай файл неявно. |
| `Refusing to overwrite/delete a user file` | Пользовательский файл занял managed-путь или потерял marker | Не обходи защиту: перенеси файл либо выбери другой sprite-каталог и перегенерируй. |
| Нет `.svg-sprite/index.js` или имя отсутствует в autocomplete | Генерация не запускалась после изменения, пользовательский barrel не экспортирует `.svg-sprite` либо type server держит старый модуль | Запусти sprite-команду, проверь `export * from './.svg-sprite'`, затем typecheck; при необходимости перезапусти TypeScript server. |
| SVG не загружается или URL неверен | Mode не совпадает со сборщиком, неверен Webpack `publicPath` либо кастомный loader перехватил asset | Сверь mode и build-команду, проверь Asset Modules/`publicPath`, исключи generated SVG из несовместимого loader. |
| Next build расходится между SSR и браузером | Модуль сгенерирован для другого bundler/router или URL переписан вручную | Верни generated `new URL(...)`, выбери точный Next mode и перегенерируй. |
| `color` не меняет многоцветную иконку | У иконки несколько переменных или она показана через `<img>`/CSS background | Используй `<FileManagerIcon>`/`<svg><use>` и нужные `--icon-color-N`. |
| Gradient/filter выглядит неверно | Автозамена цветов не гарантирует сложные paint servers | Изучи generated SVG; при необходимости отключи `replaceColors` для спрайта или упрости источник. |
| Viewer пуст | Манифесты не созданы, glob/import не статический или неверен Client Component boundary | Сначала сгенерируй спрайты; для Vite используй literal glob, для Webpack/Next статические loaders, для App Router добавь `'use client'` только Viewer-странице. |
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к config-файлу или каталогу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и защитные markers.

View File

@@ -173,4 +173,4 @@ External stack fragment support и поведение paint servers могут
- Ручной fragment не работает для имени с пробелом: используй ID из manifest.
- Один сложный icon требует иных transforms: вынеси его в отдельный sprite; per-icon transform config отсутствует.
Target-specific запуск и проверка описаны в exact-mode файлах каталога [guides](guides/standalone.md).
Target-specific запуск и проверка описаны в exact-mode файлах каталога [guides](docs/ru/guides/standalone.md).

View File

@@ -1,46 +0,0 @@
# Программный API: операционный reference
Используй `generateSprite(source, overrides?)` как основной Node.js API.
## Из config-файла
```ts
import { generateSprite } from '@gromlab/svg-sprites'
await generateSprite('src/ui/icons/svg-sprite.config.ts')
```
`source` должен указывать на конкретный `.ts`, `.js` или `.json` файл. Имя файла произвольное; генератор не выполняет discovery. Корнем sprite-модуля и базой относительных путей становится каталог этого файла.
## Без config-файла
```ts
await generateSprite('src/ui/icons', {
mode: 'react@vite',
name: 'app',
input: './icons',
})
```
Каталог включает config-less режим. После объединения настроек `mode` обязателен.
`input?: string | string[]` по умолчанию равен `./icons`. Каждое значение задаёт папку, точный SVG-файл или glob и считается от каталога конфига либо config-less source-каталога. Папка сканируется плоско; рекурсия включается только явным glob, например `./icons/**/*.svg`. Массив объединяет источники, а элементы с префиксом `!` исключают совпадения. Каждый positive-элемент должен разрешаться хотя бы в один SVG. Итоговые файлы дедуплицируются и сортируются, а разные файлы с одинаковым basename вызывают ошибку.
## Overrides
```ts
await generateSprite('src/ui/icons/custom.json', {
mode: 'react@webpack',
input: [
'../../shared/icons/**/*.svg',
'!../../shared/icons/legacy-*.svg',
],
transform: { addTransition: false },
})
```
Порядок: `defaults → config → API overrides`. `transform` объединяется по отдельным полям; переданный `input` заменяет значение из config.
Специализированные `generateReactSprite` и `generateNextSprite` оставлены как совместимые обёртки, но для нового кода предпочитай `generateSprite`.
Для загрузки и собственной оркестрации доступны `loadSpriteConfig`, `validateSpriteConfig`, `resolveSpriteConfig`, `compileSpriteContent` и `createShapeTransform`.

View File

@@ -19,7 +19,12 @@ const guideModes = new Map([
const sectionHeadings = {
en: ['Generate the sprite', 'Debug and preview', 'Type the config'],
ru: ['Генерация спрайта', 'Дебаг и превью', 'Типизация конфига'],
ru: ['Генерация спрайта', 'Дебаг и превью'],
}
const commandPatterns = {
en: /npx --yes (?:--package=@gromlab\/svg-sprites@latest svg-sprites|@gromlab\/svg-sprites@latest)/,
ru: /npx --yes @gromlab\/svg-sprites(?:\s|$)/,
}
function markdownFiles(directory) {
@@ -46,15 +51,26 @@ test('exact-mode guides are reusable by docs and skills', () => {
heading.replace(/^## (?:\d+\. )?/, '')
))
assert.deepEqual(headings, sectionHeadings[language])
assert.match(source, /npx --yes (?:--package=@gromlab\/svg-sprites@latest svg-sprites|@gromlab\/svg-sprites@latest)/)
assert.match(source, commandPatterns[language])
if (language !== 'ru' || mode !== 'standalone') {
assert.match(source, /npm install --save-dev @gromlab\/svg-sprites/)
assert.match(source, new RegExp(`mode: '${mode.replaceAll('/', '\\/')}'`))
}
if (language === 'ru') {
assert.doesNotMatch(source, /npx --yes[^\n]*@gromlab\/svg-sprites@/)
}
const modePattern = language === 'ru'
? new RegExp(`"mode": "${mode.replaceAll('/', '\\/')}"`)
: new RegExp(`mode: '${mode.replaceAll('/', '\\/')}'`)
assert.match(source, modePattern)
assert.doesNotMatch(source, /\]\([^)]+\)/, `${language}/${file} must not depend on its location`)
const generation = source.indexOf(sectionHeadings[language][0])
const preview = source.indexOf(sectionHeadings[language][1])
assert.ok(generation < preview)
if (language === 'en') {
const typing = source.indexOf(sectionHeadings[language][2])
assert.ok(generation < preview && preview < typing)
assert.ok(preview < typing)
}
}
}
})