feat: выпустить версию 1.0.0

- добавлены отдельные режимы генерации для React, Next.js и legacy
- добавлены SpriteViewer, типизированные компоненты и безопасный codegen
- перенесена сборка AI-скила и обновлена документация
- добавлены migration guide, лицензии и проверки публикации
This commit is contained in:
2026-07-11 07:00:59 +03:00
parent 3a60b5c6ae
commit 05a0a9f7ed
76 changed files with 9456 additions and 1033 deletions

View File

@@ -0,0 +1,64 @@
---
name: svg-sprites
description: "Используй при настройке, генерации, миграции или диагностике SVG-спрайтов через @gromlab/svg-sprites. Триггеры: SVG sprite, SVG-спрайт, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon=\"...\", --icon-color-N, generated-компонент или иконка не появилась в превью и автодополнении. НЕ используй для favicon, растровых изображений, icon fonts, выбора набора иконок или inline SVG без спрайтов."
---
<!-- Generated from skills/svg-sprites/src/SKILL.md. Do not edit manually. -->
# SVG Sprites
## Назначение
Используй этот скил для работы с `@gromlab/svg-sprites`: первичной настройки, добавления и переиспользования иконок, генерации React-компонентов, подключения `SpriteViewer`, миграции legacy-конфигурации и диагностики ошибок.
Не навязывай проекту конкретную архитектуру каталогов. Сначала изучи существующие `package.json`, конфигурацию спрайта, используемый фреймворк, роутер и сборщик.
## Рабочий алгоритм
1. Определи существующий режим и не смешивай его API с другим режимом.
2. Для React выбери `react@vite` или `react@webpack` и открой соответствующий reference.
3. Для Next.js определи App Router или Pages Router, затем Turbopack или Webpack, и открой соответствующий reference.
4. Для существующего `svg-sprites.config.ts` с несколькими спрайтами используй legacy-документацию. Не мигрируй такой проект без явного запроса.
5. Изучи локальные scripts и добавляй генерацию перед `dev`, `build` и `typecheck`, если generated-файлы не хранятся в Git.
6. После изменения конфигурации или SVG запусти генерацию, затем доступную проверку типов или сборку проекта.
## Правила React и Next.js
- Используй локальный `svg-sprite.config.ts` и подходящий config helper: `defineReactSpriteConfig` или `defineNextSpriteConfig`.
- Не редактируй `generated/`, `index.ts`, `manifest.ts` и созданный генератором `.gitignore` вручную.
- Имена исходных SVG становятся допустимыми значениями prop `icon`; используй generated-компонент и его публичные типы вместо deep imports.
- Объединяй локальную папку и `inputFiles`, когда общая иконка нужна нескольким спрайтам. Не создавай копии одного SVG без необходимости.
- В Next.js generated-компонент можно использовать в Server Components, SSR и SSG. Не добавляй `'use client'` только ради иконки.
- Спрайт должен оставаться внешним asset сборщика: не переносить SVG path-данные в JavaScript и не класть generated-файл вручную в `public`.
## Цвета и трансформации
- По умолчанию генератор удаляет `width` и `height`, заменяет поддерживаемые `fill` и `stroke` на CSS-переменные и добавляет transitions.
- Для монохромной иконки сначала управляй `color`; для многоцветной используй `--icon-color-N`.
- Не обещай автоматическую замену цветов внутри внешних stylesheets, gradients, patterns, filters и значений `url(#...)` без проверки результата.
- CSS-переменные страницы работают при `<svg><use>`, но не проникают внутрь `<img>` и `background-image`.
## Превью
Для React и Next.js подключай `<SpriteViewer>` отдельной debug-страницей приложения. Передай ему manifests или lazy loaders спрайтов. Viewer поддерживает поиск, светлую и тёмную темы, настройку цветов и примеры React, SVG, IMG и CSS.
`SpriteViewer` является клиентским debug-инструментом и импортируется из `@gromlab/svg-sprites/react`; production-компоненты иконок от него не зависят.
## Диагностика
- Если имя иконки отсутствует в автодополнении, проверь входную папку и `inputFiles`, затем перезапусти генерацию.
- Если два файла имеют одинаковое имя иконки, устрани конфликт вместо выбора одного файла неявно.
- Если генератор отказывается перезаписывать файл, не удаляй защитный marker и не обходи writer: перенеси пользовательский файл или выбери другой каталог спрайта.
- Если asset не загружается, сначала проверь соответствие CLI mode реальному сборщику проекта и обработку generated SVG его asset pipeline.
- Если проект использует старый API, сверь установленную версию пакета и legacy reference перед изменениями.
## References
- [Основная документация и API](./references/README.md)
- [React + Vite](./references/docs/ru/react-vite.md)
- [React + Webpack 5](./references/docs/ru/react-webpack.md)
- [Next.js App Router](./references/docs/ru/next-app.md)
- [Next.js Pages Router](./references/docs/ru/next-pages.md)
- [Legacy mode](./references/docs/ru/legacy.md)
- [Миграция с 0.1.x](./references/docs/ru/migration-1.md)
- [Программный API](./references/docs/ru/programmatic-api.md)

View File

@@ -0,0 +1,395 @@
# @gromlab/svg-sprites
![npm](https://img.shields.io/npm/v/@gromlab/svg-sprites) ![license](https://img.shields.io/npm/l/@gromlab/svg-sprites)
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
![Preview](https://gromlab.ru/gromov/svg-sprites/media/branch/master/preview-image.png)
## Навигация
- [Возможности](#возможности)
- [Таблица поддержки](#таблица-поддержки)
- [Требования](#требования)
- [Быстрый старт](#быстрый-старт)
- [React + Vite](docs/ru/react-vite.md)
- [React + Webpack 5](docs/ru/react-webpack.md)
- [Next.js App Router](docs/ru/next-app.md)
- [Next.js Pages Router](docs/ru/next-pages.md)
- [Конфигурация](#конфигурация)
- [React](#react)
- [Next.js](#nextjs)
- [Множественные спрайты](#множественные-спрайты)
- [TypeScript](#typescript)
- [Форматы спрайтов](#форматы-спрайтов)
- [Способы отображения](#способы-отображения)
- [Трансформации](#трансформации)
- [Управление цветом иконок](#управление-цветом-иконок)
- [Кеширование](#кеширование)
- [SpriteViewer](#spriteviewer)
- [Миграция с 0.1.x](docs/ru/migration-1.md)
- [Документация](#документация)
## Возможности
- **TypeScript-friendly** — типизированные React-компоненты, union-типы и runtime-списки доступных иконок.
- **Чистая генерация** — generated-файлы автоматически исключаются из Git, спрайт не нужно вручную размещать в `public`, а генератор обновляет только принадлежащие ему файлы.
- **Общие иконки без копирования** — SVG из локальной папки и `inputFiles` объединяются в один спрайт; один файл можно использовать в нескольких спрайтах.
- **Встроенное интерактивное превью** — `<SpriteViewer>` подключается как страница приложения и показывает переданные React- и Next.js-спрайты с поиском, настройкой цветов и примерами использования.
- **Настраиваемые трансформации SVG** — удаление `width` и `height` с сохранением `viewBox`, замена исходных цветов на CSS-переменные и transitions для `fill` и `stroke`.
- **Отдельный кешируемый SVG asset** — SVG path-данные не попадают в JavaScript chunks, а сборщик выпускает файл с content hash.
- **Множественные спрайты** — независимые React- и Next.js-модули со своими компонентами, типами и SVG assets.
- **Server-first Next.js** — generated-компоненты работают в Server Components, SSR и SSG без директивы `'use client'`.
- **Форматы под разные сценарии** — React и Next.js используют `stack`, legacy-режим также поддерживает `symbol` для существующих интеграций.
## Таблица поддержки
| Среда | Ключ мода API | Статус |
|---|---|---|
| React + Vite | `react@vite` | Готово |
| React + Webpack 5 | `react@webpack` | Готово |
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Готово |
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Готово |
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Готово |
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Готово |
| Vue | — | Скоро |
| Standalone | — | Скоро |
## Требования
- Node.js 18 или новее;
- пакет распространяется только как ESM и подключается через `import`;
- React 18 или 19 требуется только для generated-компонентов и точки входа `@gromlab/svg-sprites/react`;
- для типизации subpath exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
## Быстрый старт
Для быстрого старта воспользуйтесь инструкцией для вашего стека:
- [React + Vite](docs/ru/react-vite.md)
- [React + Webpack 5](docs/ru/react-webpack.md)
- [Next.js App Router](docs/ru/next-app.md)
- [Next.js Pages Router](docs/ru/next-pages.md)
## Конфигурация
### React
```ts
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
export default defineReactSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
inputFolder: './icons',
inputFiles: [
'../../shared/icons/check.svg',
],
transform: {
removeSize: true,
replaceColors: true,
addTransition: true,
},
generatedNotice: true,
})
```
| Опция | Тип | По умолчанию | Назначение |
|---|---|---|---|
| `name` | `string` | Имя папки | Имя спрайта, компонента и публичных типов |
| `description` | `string` | Нет | Описание для типов и debug-манифеста |
| `inputFolder` | `string` | `./icons` | Папка с исходными SVG относительно конфига |
| `inputFiles` | `string[]` | `[]` | Дополнительные SVG-файлы относительно конфига |
| `transform` | `TransformOptions` | Все включены | [Настройки трансформации](#трансформации) исходных SVG |
| `generatedNotice` | `boolean` | `true` | Полное либо короткое предупреждение в generated-файлах |
`inputFolder` и `inputFiles` объединяются в один спрайт, поэтому один SVG-файл можно использовать в нескольких спрайтах без копирования. Если неявной папки `./icons` нет, но `inputFiles` заполнен, генерация продолжается только по списку. Явно указанная отсутствующая папка считается ошибкой. Одинаковые пути дедуплицируются, а разные файлы с одинаковым именем иконки считаются ошибкой.
`name` записывается в kebab-case и должно начинаться с латинской буквы. React и Next.js presets создают формат `stack`.
### Next.js
Next.js использует тот же `svg-sprite.config.ts` и набор опций. Для типизации можно использовать отдельный хелпер:
```ts
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
export default defineNextSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
inputFolder: './icons',
})
```
Роутер и сборщик выбираются через mode key, поэтому переключение между Turbopack и Webpack всегда явно отражено в команде генерации.
## Множественные спрайты
Приложение может содержать несколько независимых спрайтов с разной областью использования:
**Проблема:** один глобальный спрайт загружает иконки, которые текущему экрану не нужны.
**Решение:** общие иконки хранить глобально, а наборы страниц и крупных компонентов — в отдельных спрайтах, загружаемых вместе с ними.
```text
global → GlobalIcon → общие иконки приложения
analytics-page → AnalyticsPageIcon → иконки отдельной страницы
file-manager → FileManagerIcon → иконки крупного компонента
```
- **Глобальный спрайт** содержит небольшие общие иконки, используемые в разных частях приложения: навигацию, состояния и базовые действия.
- **Спрайт страницы** загружается вместе с конкретным разделом и не увеличивает общий спрайт иконками, которые больше нигде не нужны.
- **Спрайт крупного компонента** инкапсулирует собственный набор иконок сложного UI-модуля, например файлового менеджера или редактора.
Каждая группа получает:
- собственный SVG asset;
- собственный типизированный компонент;
- отдельный список имён иконок;
- отдельный debug-манифест;
- независимый cache lifecycle.
## TypeScript
Главная возможность TypeScript API — автодополнение имён иконок непосредственно в prop `icon`:
```tsx
<FileManagerIcon icon="folder" />
// ↑ редактор предлагает все иконки спрайта
```
Имена SVG-файлов становятся допустимыми значениями `icon`. Опечатка или неизвестное имя сразу становятся ошибкой TypeScript:
```tsx
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
```
Для программного доступа generated-модуль экспортирует readonly-массив всех доступных иконок конкретного спрайта:
```ts
import { fileManagerIconNames } from './svg-sprite'
// readonly ['check', 'folder', ...]
```
Этот список можно использовать в собственных каталогах, select-компонентах, тестах и других runtime-сценариях. Из него также выводится union-тип `FileManagerIconName`.
Имена файлов с пробелами и другими небезопасными для SVG ID символами остаются частью публичного TypeScript API. Для внутреннего `<symbol id>` генератор создаёт стабильный hash ID.
```text
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
```
Для таких имён используйте generated-компонент или `id` из debug-манифеста. Ручные примеры ниже с `#<имя>` подходят только для имён, которые уже являются безопасными SVG ID.
## Форматы спрайтов
`stack` — более современный формат, поэтому он используется по умолчанию. Иконки можно отображать через `<svg><use>`, `<img>` и CSS `background-image`.
`symbol` сохраняется для совместимости с существующими интеграциями и поддерживает отображение только через `<svg><use>`.
## Способы отображения
### React-компонент — рекомендуется
Generated-компонент предоставляет типизацию, автодополнение имён иконок и сам формирует URL SVG asset.
```tsx
<FileManagerIcon icon="check" width={24} height={24} />
```
Через `color` и `--icon-color-N` доступны одноцветные и многоцветные иконки.
### Самостоятельно через `<svg><use>`
Хороший низкоуровневый способ с полным управлением размерами и цветами. React-компонент под капотом использует именно его.
Способ получения `spriteUrl` зависит от сборщика.
**Vite:**
```tsx
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
```
**Webpack 5:**
```tsx
const spriteUrl = new URL(
'./svg-sprite/generated/sprite.svg',
import.meta.url,
).href
```
**Next.js с Webpack 5 или Turbopack:**
```tsx
const spriteUrl = new URL(
'./svg-sprite/generated/sprite.svg',
import.meta.url,
).href
```
После получения URL иконка отображается одинаково:
```tsx
<svg width={24} height={24}>
<use href={`${spriteUrl}#check`} />
</svg>
```
Vite, Webpack 5 и Next.js сами заменяют исходный путь на итоговый URL asset с hash.
### Через `<img>` — менее эффективно
```tsx
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Готово" />
```
SVG загружается как изолированное изображение: изменить его цвета через `color` или `--icon-color-N` нельзя.
### Через CSS `background-image` — менее эффективно
```css
.icon {
background: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
}
```
Как и `<img>`, этот способ не позволяет управлять внутренними цветами SVG. Путь указывается относительно CSS-файла, а Vite/Webpack заменяет его на итоговый URL с hash при сборке.
### Через CSS mask — менее эффективно
```css
.icon {
background-color: currentColor;
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
}
```
Mask оставляет только силуэт и окрашивает его одним цветом. Исходные цвета, gradients и различия между `fill` и `stroke` теряются.
## Трансформации
Все трансформации включены по умолчанию и настраиваются независимо через `transform`.
| Опция | По умолчанию | Что делает |
|---|---|---|
| `removeSize` | `true` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox`. Размер иконки после этого задаётся снаружи. |
| `replaceColors` | `true` | Заменяет цвета `fill` и `stroke` на `--icon-color-N`. Для одноцветной иконки fallback становится `currentColor`, для многоцветной сохраняются исходные цвета. |
| `addTransition` | `true` | Добавляет `style="transition:fill 0.3s,stroke 0.3s;"` непосредственно цветным элементам SVG. Существующий `transition` не перезаписывается. |
Чтобы отключить преобразование, передайте для соответствующей опции `false`. Подробнее о результате `replaceColors` — в разделе [«Управление цветом иконок»](#управление-цветом-иконок).
## Управление цветом иконок
При включённой замене цветов генератор анализирует `fill` и `stroke` и преобразует их в CSS custom properties.
### Монохромные иконки
Если найден один цвет, fallback заменяется на `currentColor`:
```svg
stroke="var(--icon-color-1, currentColor)"
```
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
### Многоцветные иконки
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
```svg
fill="var(--icon-color-1, #798198)"
fill="var(--icon-color-2, #ffffff)"
fill="var(--icon-color-3, #129d9d)"
```
Страница может заменить только необходимые цвета:
```css
.icon {
--icon-color-1: #4b5563;
--icon-color-3: #14b8a6;
}
```
### Ограничения цветов
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
- цвета в атрибутах `fill`, `stroke` и inline `style` обрабатываются надёжнее всего;
- CSS-классы и внешние stylesheets внутри исходного SVG не являются основным сценарием трансформации;
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
## Кеширование
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
```text
/assets/sprite-<hash>.svg
```
Это даёт следующие свойства:
- SVG кешируется независимо от JavaScript;
- изменение React-кода не меняет содержимое спрайта;
- изменение иконок создаёт новый hash asset;
- один файл используется всеми экземплярами generated-компонента;
- SVG path-данные отсутствуют в JavaScript chunks.
Vite target запрещает inline через `?no-inline`. Webpack 5 target использует Asset Modules через `new URL(..., import.meta.url)`.
## SpriteViewer
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
Он использует отдельные манифесты и показывает:
- группы спрайтов;
- список и количество иконок;
- поиск и системную светлую/тёмную тему;
- модальное превью с `viewBox` и настройкой цветовых переменных;
- примеры React, SVG, IMG и CSS с копированием кода.
Production-компоненты не импортируют debug-манифесты. Способ подключения Viewer зависит от сборщика:
- [React + Vite: автоматический `import.meta.glob`](docs/ru/react-vite.md#6-добавьте-debug-страницу);
- [React + Webpack 5: статические `import()`](docs/ru/react-webpack.md#6-добавьте-debug-страницу);
- [Next.js App Router](docs/ru/next-app.md#5-добавьте-spriteviewer);
- [Next.js Pages Router](docs/ru/next-pages.md#5-добавьте-spriteviewer).
Viewer подключается из отдельной клиентской точки входа `@gromlab/svg-sprites/react` и не попадает в production-компоненты иконок.
### Тема Viewer
По умолчанию `colorTheme="auto"`: Viewer следует `prefers-color-scheme` и реагирует на смену системной темы. Тему приложения можно передать явно:
```tsx
<SpriteViewer sources={sources} colorTheme="dark" />
```
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
```tsx
<SpriteViewer
sources={sources}
colorTheme={appTheme}
onColorThemeChange={setAppTheme}
/>
```
## Документация
- [React + Vite](docs/ru/react-vite.md)
- [React + Webpack 5](docs/ru/react-webpack.md)
- [Next.js App Router](docs/ru/next-app.md)
- [Next.js Pages Router](docs/ru/next-pages.md)
- [Legacy mode](docs/ru/legacy.md)
- [Миграция с 0.1.x](docs/ru/migration-1.md)
- [Программный API](docs/ru/programmatic-api.md)
## Лицензия
MIT

View File

@@ -0,0 +1,102 @@
# Legacy mode
[← Главная](../../README.md)
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
## 1. Установите пакет
```bash
npm install @gromlab/svg-sprites
```
## 2. Подготовьте иконки и конфиг
```text
project/
├── src/assets/icons/
│ ├── check.svg
│ └── folder.svg
└── svg-sprites.config.ts
```
```ts
// svg-sprites.config.ts
import { defineLegacyConfig } from '@gromlab/svg-sprites'
export default defineLegacyConfig({
output: 'public/sprites',
preview: true,
sprites: [
{
name: 'icons',
input: 'src/assets/icons',
format: 'symbol',
},
],
})
```
## 3. Запустите генерацию
```bash
npx svg-sprites --mode legacy .
```
Результат:
```text
public/sprites/
├── icons.sprite.svg
└── preview.html
```
При `preview: false` HTML-файл не создаётся. Для формата `stack` укажите `format: 'stack'`.
## 4. Используйте symbol-спрайт
```html
<svg width="24" height="24" aria-label="Готово">
<use href="/sprites/icons.sprite.svg#check"></use>
</svg>
```
## 5. Добавьте package script
```json
{
"scripts": {
"sprites": "svg-sprites --mode legacy .",
"prebuild": "npm run sprites"
}
}
```
## Несколько спрайтов
Добавьте несколько записей в `sprites`:
```ts
sprites: [
{
name: 'icons',
input: 'src/assets/icons',
format: 'symbol',
},
{
name: 'logos',
input: 'src/assets/logos',
format: 'stack',
},
]
```
Все результаты и общий `preview.html` будут записаны в `output`.
## Если что-то не работает
- Не найден конфиг: убедитесь, что `svg-sprites.config.ts` находится в переданном корне.
- Нет иконок: проверьте `sprites[].input` и расширение `.svg`.
- Не нужен preview: установите `preview: false`.
Для программного запуска используйте [`generateLegacy`](programmatic-api.md#generatelegacy).

View File

@@ -0,0 +1,96 @@
# Миграция с 0.1.x на 1.0
[← Главная](../../README.md)
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
## CLI
CLI теперь всегда требует явный `--mode` и путь к каталогу конфигурации:
```text
svg-sprites
→ svg-sprites --mode <mode> <path>
```
Выберите mode по окружению:
| Окружение | Mode |
|---|---|
| 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` |
| Централизованная старая схема | `legacy` |
## React и Next.js
Вместо корневого `svg-sprites.config.ts` создайте локальный `svg-sprite.config.ts` рядом с набором иконок:
```ts
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
export default defineNextSpriteConfig({
name: 'global',
inputFolder: './icons',
})
```
Для обычного React используйте `defineReactSpriteConfig`. Папку и явный список общих SVG можно объединить через `inputFolder` и `inputFiles`.
Старые `publicPath` и `react` больше не нужны. Generated-модуль создаётся рядом с конфигом, сам добавляет `.gitignore`, а Vite, Webpack или Next.js выпускает SVG как отдельный asset с content hash.
Компонент `<SvgSprite icon="..." />` заменяется компонентом, имя которого выводится из `name`:
```tsx
<GlobalIcon icon="check" />
```
Для просмотра иконок добавьте `<SpriteViewer>` как debug-страницу приложения. Отдельный `preview.html` остаётся только в legacy-режиме.
## Legacy-режим
Если централизованную структуру нужно сохранить, переименуйте helper и поля формата:
```ts
import { defineLegacyConfig } from '@gromlab/svg-sprites'
export default defineLegacyConfig({
output: 'public/sprites',
preview: true,
sprites: [
{
name: 'icons',
input: 'src/assets/icons',
format: 'stack',
},
],
})
```
- `defineConfig` заменён на `defineLegacyConfig`;
- `sprites[].mode` переименован в `sprites[].format`;
- `generate` заменён на `generateLegacy`;
- `loadConfig` заменён на `loadLegacyConfig`;
- `publicPath` и генерация старого общего React-компонента удалены.
Запуск:
```bash
svg-sprites --mode legacy .
```
## Программный API
Пакет распространяется только как ESM. Замените `require()` на `import`.
`compileSpriteContent` теперь возвращает `Promise<Uint8Array>`, чтобы публичные декларации не требовали установки `@types/node`. В Node.js фактический результат совместим с API, принимающими `Uint8Array`.
## После миграции
1. Удалите старые generated-файлы и правила, которые игнорировали целиком каталог с исходными иконками.
2. Добавьте явную команду генерации перед `dev`, `build` и `typecheck`.
3. Запустите генерацию и проверку типов.
4. Проверьте все иконки и цветовые переменные через `SpriteViewer` или legacy `preview.html`.

View File

@@ -0,0 +1,102 @@
# Next.js App Router
[← Главная](../../README.md)
Поддерживаются два явных режима:
| Сборщик | Mode key | Версия Next.js |
|---|---|---|
| Turbopack | `next@app/turbopack` | 16.2+ |
| Webpack 5 | `next@app/webpack` | 13.4+ |
## 1. Установите пакет
```bash
npm install @gromlab/svg-sprites
```
## 2. Создайте sprite-модуль
```text
src/ui/file-manager/svg-sprite/
├── icons/
│ ├── check.svg
│ └── folder.svg
└── svg-sprite.config.ts
```
```ts
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
export default defineNextSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
})
```
## 3. Добавьте генерацию
Для Turbopack:
```json
{
"scripts": {
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
"predev": "npm run sprite:file-manager",
"prebuild": "npm run sprite:file-manager"
}
}
```
Для Webpack замените mode key на `next@app/webpack`. В Next 1315 Webpack используется обычной командой `next build`, в Next 16 — командой `next build --webpack`.
## 4. Используйте в Server Component
Generated-компонент не содержит `'use client'`, поэтому его можно импортировать непосредственно в `page.tsx` или `layout.tsx`:
```tsx
import { FileManagerIcon } from '@/ui/file-manager/svg-sprite'
export default function Page() {
return (
<main>
<FileManagerIcon icon="folder" width={24} height={24} />
</main>
)
}
```
Next.js выпустит отдельный SVG asset с content hash. Один generated-код используется при SSR и в браузере без расхождения URL.
## 5. Добавьте SpriteViewer
Viewer интерактивен, поэтому для него нужна отдельная Client Component граница:
```tsx
'use client'
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('@/ui/file-manager/svg-sprite/manifest'),
]
export default function SpritesPage() {
return <SpriteViewer sources={sources} />
}
```
## Проверка сборщика
```bash
# Turbopack
npx next build --turbopack
# Webpack 5
npx next build --webpack
```
Для Next 1315 с Webpack используйте `npx next build` без флага.
Команда Next.js и mode key генератора должны указывать один и тот же сборщик.

View File

@@ -0,0 +1,96 @@
# Next.js Pages Router
[← Главная](../../README.md)
Поддерживаются два явных режима:
| Сборщик | Mode key | Версия Next.js |
|---|---|---|
| Turbopack | `next@pages/turbopack` | 16.2+ |
| Webpack 5 | `next@pages/webpack` | 12.2+ |
Для Next.js 12.2 требуется React 18.
## 1. Установите пакет
```bash
npm install @gromlab/svg-sprites
```
## 2. Создайте sprite-модуль
```text
src/ui/file-manager/svg-sprite/
├── icons/
│ ├── check.svg
│ └── folder.svg
└── svg-sprite.config.ts
```
```ts
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
export default defineNextSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
})
```
## 3. Добавьте генерацию
```json
{
"scripts": {
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
"predev": "npm run sprite:file-manager",
"prebuild": "npm run sprite:file-manager"
}
}
```
Для Next.js 16.2 с Turbopack замените mode key на `next@pages/turbopack`.
## 4. Используйте на странице
```tsx
import { FileManagerIcon } from '@/ui/file-manager/svg-sprite'
export default function FilesPage() {
return <FileManagerIcon icon="folder" width={24} height={24} />
}
export function getServerSideProps() {
return { props: {} }
}
```
Компонент одинаково работает при SSR, SSG и клиентских переходах. Next.js выпускает отдельный SVG asset с content hash.
## 5. Добавьте SpriteViewer
```tsx
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('@/ui/file-manager/svg-sprite/manifest'),
]
export default function SpritesPage() {
return <SpriteViewer sources={sources} />
}
```
## Проверка сборщика
```bash
# Turbopack
npx next build --turbopack
# Webpack 5
npx next build --webpack
```
Для Next 1215 с Webpack используйте `npx next build` без флага.
Команда Next.js и mode key генератора должны указывать один и тот же сборщик.

View File

@@ -0,0 +1,203 @@
# Программный API
[← Главная](../../README.md)
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
Для разрешения `@gromlab/svg-sprites/react` в TypeScript используйте `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
## Основной entry
```ts
import {
defineNextSpriteConfig,
defineReactSpriteConfig,
generateNextSprite,
generateReactSprite,
} from '@gromlab/svg-sprites'
```
Основной entry не импортирует React и может использоваться в CLI, build scripts и Node.js инструментах.
## `generateReactSprite`
```ts
import { generateReactSprite } from '@gromlab/svg-sprites'
const result = await generateReactSprite(
'src/ui/file-manager/svg-sprite',
'vite',
)
```
Второй аргумент обязателен:
```ts
type ReactAssetTarget = 'vite' | 'webpack'
```
Результат:
```ts
type ReactSpriteGenerationResult = {
name: string
rootDir: string
generatedDir: string
spritePath: string
manifestPath: string
iconCount: number
target: 'vite' | 'webpack'
}
```
```ts
console.log(result.name)
console.log(result.iconCount)
console.log(result.spritePath)
console.log(result.manifestPath)
```
Функция загружает `svg-sprite.config.ts` из указанного корня, компилирует SVG и безопасно обновляет managed-файлы.
## `generateNextSprite`
```ts
import { generateNextSprite } from '@gromlab/svg-sprites'
const result = await generateNextSprite(
'src/ui/file-manager/svg-sprite',
{
router: 'app',
bundler: 'turbopack',
},
)
```
Доступные значения:
```ts
type NextSpriteGenerationOptions = {
router: 'app' | 'pages'
bundler: 'turbopack' | 'webpack'
}
```
Результат дополнительно содержит выбранные `router`, `bundler` и полный target вида `next@app/turbopack`.
## `defineReactSpriteConfig`
```ts
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
export default defineReactSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
inputFolder: './icons',
inputFiles: [
'../../shared/icons/check.svg',
],
transform: {
removeSize: true,
replaceColors: true,
addTransition: true,
},
generatedNotice: true,
})
```
`inputFolder` и `inputFiles` объединяются. Хелпер возвращает конфиг без runtime-преобразований и предоставляет TypeScript autocomplete.
## `defineNextSpriteConfig`
```ts
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
export default defineNextSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
inputFolder: './icons',
})
```
Next.js использует тот же контракт конфигурации, что и React presets.
## `generateLegacy`
```ts
import { generateLegacy } from '@gromlab/svg-sprites'
const results = await generateLegacy({
output: 'public/sprites',
preview: false,
sprites: [
{
name: 'icons',
input: 'src/assets/icons',
format: 'symbol',
},
],
})
```
Возвращается массив:
```ts
type SpriteResult = {
name: string
format: 'symbol' | 'stack'
spritePath: string
iconCount: number
}
```
Подробнее: [Legacy mode](legacy.md).
## Низкоуровневые функции
Основная точка входа также экспортирует:
```ts
import {
compileSprite,
compileSpriteContent,
createShapeTransform,
generatePreview,
loadLegacyConfig,
loadReactSpriteConfig,
resolveSpriteEntry,
resolveSprites,
} from '@gromlab/svg-sprites'
```
Эти функции предназначены для собственного orchestration поверх существующего compiler и writer. Для стандартного использования предпочтительны `generateReactSprite` и `generateLegacy`.
## React runtime entry
```tsx
import { SpriteViewer } from '@gromlab/svg-sprites/react'
```
Типы:
```ts
import type {
SpriteManifest,
SpriteManifestColor,
SpriteManifestIcon,
SpriteManifestLoader,
SpriteManifestModule,
SpriteViewerColorTheme,
SpriteViewerProps,
SpriteViewerSource,
SpriteViewerSources,
} from '@gromlab/svg-sprites/react'
```
React entry содержит `'use client'` и предназначен для debug-инструментов. Generated production-компоненты импортируются из локальных sprite-модулей приложения, а не из React entry пакета.
`SpriteViewerProps.colorTheme` принимает `auto | light | dark`. Значение `auto` используется по умолчанию и следует `prefers-color-scheme`; для синхронизации с темой приложения передавайте вычисленное `light` или `dark`.
## Связанные руководства
- [React + Vite](react-vite.md)
- [React + Webpack 5](react-webpack.md)

View File

@@ -0,0 +1,116 @@
# React + Vite
[← Главная](../../README.md)
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Vite.
В результате вы получите типизированный React-компонент и отдельный кешируемый SVG asset.
## 1. Установите пакет
```bash
npm install @gromlab/svg-sprites
```
## 2. Создайте папку спрайта
```text
src/ui/file-manager/svg-sprite/
├── icons/
│ ├── check.svg
│ └── folder.svg
└── svg-sprite.config.ts
```
Поместите исходные SVG-файлы в `icons/`.
## 3. Добавьте конфиг
```ts
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
export default defineReactSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
})
```
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
Полный список опций находится в разделе [Конфигурация → React](../../README.md#react).
## 4. Добавьте генерацию в package.json
```json
{
"scripts": {
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
"predev": "npm run sprite:file-manager",
"prebuild": "npm run sprite:file-manager",
"pretypecheck": "npm run sprite:file-manager"
}
}
```
Generated-файлы исключаются из Git, поэтому генерация должна выполняться перед `dev`, `build` и `typecheck`.
Первый запуск:
```bash
npm run sprite:file-manager
```
## 5. Используйте компонент
Имя `file-manager` преобразуется в `FileManagerIcon`:
```tsx
import { FileManagerIcon } from './svg-sprite'
export const OpenFolderButton = () => (
<button type="button">
<FileManagerIcon icon="folder" width={24} height={24} />
Открыть
</button>
)
```
Значение `icon` проверяется TypeScript по именам файлов:
```tsx
<FileManagerIcon icon="check" /> // допустимо
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
```
Типы, способы отображения и управление цветами описаны в [основной документации](../../README.md#способы-отображения).
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
## 6. Добавьте debug-страницу
После подключения иконок можно вывести все React-спрайты через `SpriteViewer`:
```tsx
import { SpriteViewer } from '@gromlab/svg-sprites/react'
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
const sources = import.meta.glob<SpriteManifestModule>(
'/src/**/svg-sprite/manifest.ts',
)
export const IconsDebugPage = () => (
<SpriteViewer sources={sources} title="Иконки проекта" />
)
```
Vite автоматически найдёт generated `manifest.ts` каждого React-спрайта. Шаблон `import.meta.glob` должен быть строковым литералом, а генерация должна выполниться до запуска Vite.
Размещайте Viewer только на debug-маршруте или во внутреннем инструменте.
## Если что-то не работает
- Нет `index.ts`: запустите `npm run sprite:file-manager`.
- Viewer не видит спрайт: проверьте путь glob и наличие `manifest.ts`.
- Ошибка `Refusing to overwrite a user file`: в generated-пути находится пользовательский файл.
- Иконка не меняет цвет: используйте `color` или `--icon-color-N`.

View File

@@ -0,0 +1,118 @@
# React + Webpack 5
[← Главная](../../README.md)
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Webpack 5.
В результате вы получите типизированный React-компонент и отдельный SVG asset через Webpack Asset Modules.
## 1. Установите пакет
```bash
npm install @gromlab/svg-sprites
```
## 2. Создайте папку спрайта
```text
src/ui/file-manager/svg-sprite/
├── icons/
│ ├── check.svg
│ └── folder.svg
└── svg-sprite.config.ts
```
Поместите исходные SVG-файлы в `icons/`.
## 3. Добавьте конфиг
```ts
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
export default defineReactSpriteConfig({
name: 'file-manager',
description: 'Иконки файлового менеджера',
})
```
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
Полный список опций находится в разделе [Конфигурация → React](../../README.md#react).
## 4. Добавьте генерацию в package.json
```json
{
"scripts": {
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
"predev": "npm run sprite:file-manager",
"prebuild": "npm run sprite:file-manager",
"pretypecheck": "npm run sprite:file-manager"
}
}
```
Generated-файлы исключаются из Git, поэтому генерация должна выполняться перед `dev`, `build` и `typecheck`.
Первый запуск:
```bash
npm run sprite:file-manager
```
## 5. Используйте компонент
```tsx
import { FileManagerIcon } from './svg-sprite'
export const OpenFolderButton = () => (
<button type="button">
<FileManagerIcon icon="folder" width={24} height={24} />
Открыть
</button>
)
```
Значение `icon` проверяется TypeScript по именам файлов:
```tsx
<FileManagerIcon icon="folder" /> // допустимо
<FileManagerIcon icon="missing" /> // ошибка TypeScript
```
Типы, способы отображения и управление цветами описаны в [основной документации](../../README.md#способы-отображения).
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
Если проект уже использует собственный SVG loader, убедитесь, что он не перехватывает generated `sprite.svg` вместо Asset Modules.
## 6. Добавьте debug-страницу
Webpack не поддерживает Vite API `import.meta.glob`, поэтому передайте статические loaders:
```tsx
import { SpriteViewer } from '@gromlab/svg-sprites/react'
const sources = [
() => import('./ui/file-manager/svg-sprite/manifest'),
() => import('./ui/navigation/svg-sprite/manifest'),
]
export const IconsDebugPage = () => (
<SpriteViewer sources={sources} title="Иконки проекта" />
)
```
Пути в `import()` должны быть строковыми литералами. Webpack создаст chunks для манифестов и свяжет их с SVG assets.
Размещайте Viewer только на debug-маршруте или во внутреннем инструменте.
## Если что-то не работает
- Нет `index.ts`: запустите `npm run sprite:file-manager`.
- Viewer не загружает спрайт: проверьте путь в `import()` и наличие `manifest.ts`.
- Неверный URL asset: проверьте `output.publicPath`.
- SVG перехватывает другой loader: исключите generated sprite из несовместимого правила.
Для Next.js используйте отдельные mode key из руководств [App Router](next-app.md) и [Pages Router](next-pages.md).