feat: добавить серверную генерацию спрайтов

This commit is contained in:
2026-07-16 09:14:11 +03:00
parent e9ae91815a
commit 57342fae4e
379 changed files with 3108 additions and 655 deletions

View File

@@ -48,7 +48,7 @@ const russianDocumentation = [
export default [
{
name: 'svg-sprites',
description: 'Use only when configuring, generating, or troubleshooting @gromlab/svg-sprites. Triggers: @gromlab/svg-sprites, svg-sprite.config.json, defineSpriteConfig, generateSprite, exact modes for standalone, React, Next.js, Vue, Nuxt, Svelte, Angular, Astro, Solid, Preact, Qwik, Lit, or Alpine.js, SpriteConfig.input, --input, SpriteViewer, or --icon-color-N. Do NOT use for custom SVG sprites, favicons, raster images, icon fonts, choosing an icon set, or inline SVG without this package.',
description: 'Use only when configuring, generating, or troubleshooting @gromlab/svg-sprites. Triggers: @gromlab/svg-sprites, svg-sprite.config.json, defineSpriteConfig, generateSprite, standalone@server, source: remote, ServerSvgInput, exact modes for standalone, React, Next.js, Vue, Nuxt, Svelte, Angular, Astro, Solid, Preact, Qwik, Lit, or Alpine.js, SpriteConfig.input, --input, SpriteViewer, or --icon-color-N. Do NOT use for custom SVG sprites, favicons, raster images, icon fonts, choosing an icon set, or inline SVG without this package.',
output: '../artifacts/svg-sprites',
maxSkillBytes: 48_000,
documents: documents('en'),
@@ -56,7 +56,7 @@ export default [
},
{
name: 'svg-sprites-ru',
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.json, defineSpriteConfig, generateSprite, exact modes для standalone, React, Next.js, Vue, Nuxt, Svelte, Angular, Astro, Solid, Preact, Qwik, Lit или Alpine.js, SpriteConfig.input, --input, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.json, defineSpriteConfig, generateSprite, standalone@server, source: remote, ServerSvgInput, exact modes для standalone, React, Next.js, Vue, Nuxt, Svelte, Angular, Astro, Solid, Preact, Qwik, Lit или Alpine.js, SpriteConfig.input, --input, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
output: '../artifacts/svg-sprites-ru',
maxSkillBytes: 48_000,
documents: documents('ru'),

View File

@@ -12,11 +12,17 @@ The package supports multiple independent sprites in one project. Each explicitl
- an isolated framework-native component and declarations for framework modes;
- a native Web Component with an explicit registration function for `standalone@vite`/`standalone@webpack`;
- a deployment-neutral JSON manifest without a public URL for bare `standalone`.
- a content-addressed server release with two compile profiles and an integrity manifest for `standalone@server`.
The project determines how many sprite directories exist and where they live. For example, `name: 'file-manager'` produces `FileManagerIcon`, `FileManagerIconName`, and `fileManagerIconNames`, while another directory with `name: 'navigation'` produces a separate `NavigationIcon`. These are examples of per-sprite APIs, not fixed package exports.
Generated production runtime and declarations do not import `@gromlab/svg-sprites`. Generation through `npx --yes @gromlab/svg-sprites <path-to-config>` does not add the package to the project. Install it as a development dependency only for the Viewer, package-provided config types, or the programmatic API.
Any consumer exact mode can use `source: 'remote'` with one local path or HTTP(S)
URL to a manifest produced by `standalone@server`. Generation verifies and downloads
the required profile before the adapter creates its normal local API and asset; the
browser never depends on the server manifest at runtime.
## Selecting a mode
Select exactly one supported mode key:
@@ -26,6 +32,7 @@ Select exactly one supported mode key:
| Static HTML / custom publishing | `standalone` |
| Standalone + Vite | `standalone@vite` |
| Standalone + Webpack 5 | `standalone@webpack` |
| Server or CI release | `standalone@server` |
| React + Vite | `react@vite` |
| React + Webpack 5 | `react@webpack` |
| Vue + Vite | `vue@vite` |
@@ -68,7 +75,7 @@ The CLI accepts exactly one path. A `.ts`, `.js`, or `.json` file loads that exa
}
```
Generation through `npx` does not add the package to the project. Do not invent shortened or generic mode keys, and do not use the removed `legacy` mode. Select one complete key from the table. Use bare `standalone` only when the application publishes the SVG itself. Create one command per config file or directory when the project has multiple sprites.
Generation through `npx` does not add the package to the project. Do not invent shortened or generic mode keys, and do not use the removed `legacy` mode. Select one complete key from the table. Use bare `standalone` only when the application publishes the SVG itself, and `standalone@server` only for a centralized release consumed during generation. Create one command per config file or directory when the project has multiple sprites.
## Inspecting the project
@@ -81,7 +88,7 @@ Establish the project's actual contract before making changes:
5. For a new sprite, choose a target directory without imposing a particular application layer or architecture.
6. Check TypeScript and alias settings. Package subpath exports require TypeScript 5+ with `moduleResolution: 'bundler'`, `'node16'`, or `'nodenext'`.
All input paths are relative to the directory containing the explicitly selected config file; in config-less mode they are relative to the supplied directory. Inspect `input` using this single contract:
For a regular local consumer, all input paths are relative to the directory containing the explicitly selected config file; in config-less mode they are relative to the supplied directory. Inspect local `input` using this contract:
- `input?: string | string[]` defaults to `./icons`;
- each string is a folder, an exact SVG file, or a glob;
@@ -91,6 +98,12 @@ All input paths are relative to the directory containing the explicitly selected
- resolved files are deduplicated and sorted deterministically;
- different files with the same basename are a conflict, even when they came from different sources.
Branch before applying those rules:
- `standalone@server` may combine local strings with `{ name, url, sha256? }` HTTP(S) descriptors; `name` is the public icon name and optional `sha256` verifies the downloaded bytes;
- `source: 'remote'` requires exactly one string containing a local manifest path or HTTP(S) manifest URL and does not accept source globs or descriptors;
- a remote consumer config contains only `mode`, `source`, and `input`; name, description, transforms, and generated notice come from the verified server manifest.
Do not copy a shared SVG into several folders: add its exact path or a suitable glob to `input` in every sprite that needs it. Use `**/*.svg` only when recursive inclusion is intentional.
## Setting up the integration
@@ -108,6 +121,12 @@ Work in this order:
7. If the application imports the sprite-module directory, create a user-owned `index.ts` next to `.svg-sprite`; do not place user files inside the generated directory.
8. Run the first generation before typecheck or application startup, then inspect the mode-specific output and the actual component import.
For a centralized release, open `references/docs/en/guides/standalone-server.md`.
Generate and publish the complete `.svg-sprite` directory atomically. In each consumer,
retain its own exact framework mode, set `source: 'remote'`, and point `input` to that
manifest. Do not copy server files into a framework output or fetch the manifest from
application runtime.
Do not add the Viewer automatically. Connect it only when requested or when visual verification of the set, colors, or complex SVGs is needed. Get the production isolation pattern from the exact guide: frameworks, bundlers, and routers use different boundaries.
Do not copy snippets between exact modes even when their APIs look similar. Asset URLs, generated files, CSS handling, router boundaries, and debug-tool setup differ.
@@ -138,6 +157,12 @@ svg-sprite/
Standalone modes do not create `react/`. Bare `standalone` generates `sprite.svg` and `svg-sprite.manifest.json`; `standalone@vite`/`standalone@webpack` additionally generate `index.*`, `icon-data.*`, and a resolved manifest. Their `index.*` also contains a native generated Web Component; bare `standalone` gets no JavaScript runtime and does not create `.gitignore`.
`standalone@server` generates `sprite.<content-hash>.svg`,
`sprite-root-viewbox.<content-hash>.svg`, and `svg-sprite.manifest.json`. It has no
consumer facade, browser runtime, Viewer entry, or `.gitignore`. The manifest records
both relative profile URLs, full SHA-256 digests, byte lengths, icon metadata, and
transform settings.
Edit the source SVGs, selected config, and user-owned `index.ts`. Do not manually change anything in `.svg-sprite`: the next generation will overwrite it. In every mode except bare `standalone`, the generated `.gitignore` is also managed by the generator. To import from the sprite-module root, create a barrel:
```ts
@@ -157,6 +182,7 @@ In bundler modes, the sprite remains a separate asset and SVG path data is not e
- a custom Webpack SVG loader must not intercept the generated `sprite.svg`;
- in Next mode, the generated component does not contain `'use client'` and works in Server Components, SSR, and SSG; do not add a client boundary solely for an icon;
- the Next build command and mode key must agree: Turbopack with `.../turbopack`, Webpack with `.../webpack`.
- remote consumers still publish through their own adapter's local asset pipeline; do not preserve or construct the server profile URL in generated application code.
For bundler modes, do not move the generated sprite into `public` or rewrite its URL manually. For bare `standalone`, do not move the managed original: the application may explicitly copy it into deploy output and owns the public URL and stale-copy cleanup. Regenerate with the new complete key when changing mode.
@@ -229,8 +255,9 @@ After changing a config or SVG, perform these required checks:
1. Run the exact sprite command. It must exit with code `0` and report the name, icon count, mode, and `.svg-sprite` directory.
2. Inspect the output for the selected exact mode:
- bare `standalone` creates `sprite.svg` and `svg-sprite.manifest.json`;
- `standalone@vite` and `standalone@webpack` additionally create `index.*`, `icon-data.*`, and a JS manifest, but no `react/` directory;
- bare `standalone` creates `sprite.svg` and `svg-sprite.manifest.json`;
- `standalone@server` creates two content-addressed SVG profiles and a server manifest whose hashes and relative paths match those files;
- `standalone@vite` and `standalone@webpack` additionally create `index.*`, `icon-data.*`, and a JS manifest, but no `react/` directory;
- framework modes also create their adapter-owned native component runtime, declaration, and styles.
3. For modes with a public facade, inspect `.svg-sprite/index.js`, the adjacent `index.d.ts`, the name list, and the actual import through the user-owned barrel.
4. Inspect the manifest: mode and target must match the selected adapter, and the icon list must match the source SVGs. In bundler modes the URL must use the mode-specific mechanism; the bare JSON manifest intentionally has no public `spriteUrl`.
@@ -265,6 +292,8 @@ Match the symptom to the relevant check and fix the root cause:
| `color` does not change a multicolor icon | The icon uses several variables or is rendered through `<img>`/CSS background | Use `<FileManagerIcon>`/`<svg><use>` and the required `--icon-color-N` properties. |
| Gradient/filter renders incorrectly | Automatic color replacement cannot guarantee complex paint servers | Inspect the generated SVG; disable `replaceColors` for the sprite or simplify the source if necessary. |
| Viewer is empty | The manifest was not generated, the loader is not discoverable by the bundler, or the Client Component boundary is wrong | Generate the sprite first, then compare the manifest import and setup with the exact guide; in the App Router keep `'use client'` only in the Viewer component. |
| Remote manifest is rejected | It is not a `standalone@server` schema, contains an unsafe profile path, or its metadata is inconsistent | Publish the untouched complete server release and point `input` to its JSON manifest. |
| Remote sprite integrity check fails | The SVG is stale, truncated, or was changed independently from the manifest | Republish the manifest and both content-addressed profiles atomically; never overwrite a hashed SVG with different bytes. |
For an unknown error, record the complete CLI command, mode, config-file or directory path, and first stack/error message. Then reduce it to one sprite without deleting user files or a managed `.gitignore`.
@@ -285,6 +314,7 @@ References are included in the built skill. Open only the documents relevant to
- [`standalone`](./references/docs/en/guides/standalone.md) covers static HTML and custom SVG publishing.
- [`standalone@vite`](./references/docs/en/guides/standalone-vite.md) covers a vanilla Vite application and the Web Component.
- [`standalone@webpack`](./references/docs/en/guides/standalone-webpack.md) covers a vanilla Webpack 5 application and the Web Component.
- [`standalone@server`](./references/docs/en/guides/standalone-server.md) covers centralized content-addressed releases and remote consumers.
- [`react@vite`](./references/docs/en/guides/react-vite.md) covers React with Vite.
- [`react@webpack`](./references/docs/en/guides/react-webpack.md) covers React with Webpack 5.
- [`vue@vite`](./references/docs/en/guides/vue-vite.md) covers Vue with Vite.

View File

@@ -12,11 +12,17 @@
- для framework modes — изолированный нативный компонент и declarations;
- для `standalone@vite`/`standalone@webpack` — нативный Web Component с явной функцией регистрации;
- для bare `standalone` — deployment-neutral JSON manifest без публичного URL.
- для `standalone@server` — content-addressed server release с двумя compile profiles и integrity manifest.
Количество и расположение каталогов определяет проект. Например, `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.
Любой consumer exact mode может использовать `source: 'remote'` с одним local path
или HTTP(S) URL manifest, созданного `standalone@server`. До запуска adapter генератор
скачивает и проверяет нужный profile, после чего создаётся обычный локальный API и
asset; в runtime браузер не зависит от server manifest.
## Выбор режима
Выбери ровно один поддерживаемый mode key:
@@ -26,6 +32,7 @@ Generated production runtime и declarations не импортируют `@groml
| Static HTML / собственная публикация | `standalone` |
| Standalone + Vite | `standalone@vite` |
| Standalone + Webpack 5 | `standalone@webpack` |
| Server или CI release | `standalone@server` |
| React + Vite | `react@vite` |
| React + Webpack 5 | `react@webpack` |
| Vue + Vite | `vue@vite` |
@@ -68,7 +75,7 @@ CLI принимает ровно один путь. Путь к файлу `.ts
}
```
Генерация через `npx` не добавляет package в проект. Не придумывай сокращённые или generic mode keys и не используй удалённый `legacy`: выбери один полный key из таблицы. Bare `standalone` выбирай только когда приложение само публикует SVG. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.
Генерация через `npx` не добавляет package в проект. Не придумывай сокращённые или generic mode keys и не используй удалённый `legacy`: выбери один полный key из таблицы. Bare `standalone` выбирай только когда приложение само публикует SVG, а `standalone@server` — только для централизованного release, используемого во время генерации consumers. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.
## Инспекция проекта
@@ -81,7 +88,7 @@ CLI принимает ровно один путь. Путь к файлу `.ts
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
Все input-пути считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога. Проверяй `input` как единый контракт:
Для обычного local consumer все input-пути считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога. Проверяй local `input` по этому контракту:
- `input?: string | string[]` по умолчанию равен `./icons`;
- каждая строка задаёт папку, точный SVG-файл или glob;
@@ -91,6 +98,12 @@ CLI принимает ровно один путь. Путь к файлу `.ts
- разрешённые файлы дедуплицируются и детерминированно сортируются;
- разные файлы с одинаковым basename конфликтуют, даже если получены из разных источников.
До применения этих правил выбери нужную ветку:
- `standalone@server` может объединять local strings и HTTP(S) descriptors `{ name, url, sha256? }`; `name` задаёт публичное имя иконки, а необязательный `sha256` проверяет скачанные байты;
- `source: 'remote'` требует ровно одну строку с local path или HTTP(S) URL manifest и не принимает source globs или descriptors;
- remote consumer config содержит только `mode`, `source` и `input`; name, description, transforms и generated notice приходят из проверенного server manifest.
Не копируй общий SVG в несколько папок: добавь его точный путь или подходящий glob в `input` каждого нужного спрайта. Используй `**/*.svg` только для намеренного рекурсивного включения.
## Настройка интеграции
@@ -108,6 +121,12 @@ CLI принимает ровно один путь. Путь к файлу `.ts
7. Если приложение импортирует каталог sprite-модуля, создай пользовательский `index.ts` рядом с `.svg-sprite`; не помещай пользовательские файлы внутрь generated-каталога.
8. Выполни первую генерацию до typecheck или запуска приложения, затем проверь mode-specific output и фактический импорт компонента.
Для централизованного release открой `references/docs/ru/guides/standalone-server.md`.
Генерируй и публикуй весь каталог `.svg-sprite` атомарно. В каждом consumer сохрани
его собственный exact framework mode, укажи `source: 'remote'` и направь `input` на
manifest. Не копируй server files во framework output и не загружай manifest из
runtime приложения.
Не добавляй Viewer автоматически. Подключай его только по запросу пользователя или когда нужна визуальная проверка набора, цветов либо сложных SVG. Способ изоляции Viewer от production бери из exact guide: frameworks, bundlers и routers используют разные границы.
Не копируй snippets между exact modes даже при похожем API. Различаются asset URL, generated-файлы, CSS handling, router boundary и способ подключения debug-инструментов.
@@ -138,6 +157,12 @@ svg-sprite/
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`.
`standalone@server` генерирует `sprite.<content-hash>.svg`,
`sprite-root-viewbox.<content-hash>.svg` и `svg-sprite.manifest.json`. У него нет
consumer facade, browser runtime, Viewer entry или `.gitignore`. Manifest хранит
relative URL обоих profiles, полные SHA-256, размеры в байтах, metadata иконок и
настройки transforms.
Редактируй исходные SVG, config-файл и пользовательский `index.ts`. Не изменяй вручную содержимое `.svg-sprite`: повторная генерация его перезапишет. Во всех modes, кроме bare `standalone`, generated `.gitignore` также находится под управлением генератора. Для импорта из корня sprite-модуля создай barrel:
```ts
@@ -157,6 +182,7 @@ export * from './.svg-sprite/index.js'
- кастомный Webpack SVG loader не должен перехватывать generated `sprite.svg`;
- в Next mode generated-компонент не содержит `'use client'` и работает в Server Components, SSR и SSG; не добавляй клиентскую границу только ради иконки;
- команда сборки Next и mode key должны совпадать: Turbopack с `.../turbopack`, Webpack с `.../webpack`.
- remote consumers всё равно публикуются через локальный asset pipeline своего adapter; не сохраняй и не собирай URL server profile в generated application code.
Для bundler modes не перемещай generated sprite в `public` и не переписывай URL вручную. Для bare `standalone` не перемещай managed original: приложение может явно копировать его в deploy output и само отвечает за публичный URL и очистку копии. При смене mode перегенерируй спрайт с новым полным key.
@@ -229,8 +255,9 @@ Generated-компонент не выбирает семантику за пр
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/`;
- bare `standalone` создаёт `sprite.svg` и `svg-sprite.manifest.json`;
- `standalone@server` создаёт два content-addressed SVG profiles и server manifest, hashes и relative paths которого соответствуют этим файлам;
- `standalone@vite` и `standalone@webpack` дополнительно создают `index.*`, `icon-data.*` и JS manifest, но не каталог `react/`;
- framework modes также создают adapter-owned runtime нативного компонента, declaration и styles.
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`.
@@ -265,6 +292,8 @@ Viewer используй для сложных цветов, transforms и ма
| `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. |
| Remote manifest отклонён | Это не schema `standalone@server`, profile path небезопасен или metadata противоречивы | Опубликуй неизменённый полный server release и направь `input` на его JSON manifest. |
| Не прошла integrity-проверка remote sprite | SVG устарел, обрезан или изменён отдельно от manifest | Атомарно переопубликуй manifest и оба content-addressed profiles; никогда не перезаписывай hashed SVG другими байтами. |
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к config-файлу или каталогу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и управляемый `.gitignore`.
@@ -285,6 +314,7 @@ References являются частью собранного skill. Откры
- [`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.
- [`standalone@server`](./references/docs/ru/guides/standalone-server.md) — централизованный content-addressed release и remote consumers.
- [`react@vite`](./references/docs/ru/guides/react-vite.md) — React с Vite.
- [`react@webpack`](./references/docs/ru/guides/react-webpack.md) — React с Webpack 5.
- [`vue@vite`](./references/docs/ru/guides/vue-vite.md) — Vue с Vite.