feat: standalone mode

This commit is contained in:
2026-07-14 08:34:45 +03:00
parent 3dd385bfda
commit c596f9f1c3
64 changed files with 1341 additions and 2755 deletions

View File

@@ -14,6 +14,21 @@ const result = await generateSprite(
)
```
For static standalone mode, use `result.spritePath` in a build script to publish the
SVG under an application URL:
```ts
import { copyFile } from 'node:fs/promises'
const result = await generateSprite('src/sprite/svg-sprite.config.ts', {
mode: 'standalone',
})
await copyFile(result.spritePath, 'dist/app-icons/sprite.svg')
```
`spritePath` is a filesystem path, not a browser URL. A deployment-neutral JSON
manifest is available through `result.manifestPath` and is copied independently.
The first argument accepts the full path to an explicitly selected `.ts`, `.js`, or `.json` config file with any name. Passing a directory enables config-less mode and uses that directory as the sprite module root.
The second argument contains optional overrides and always takes precedence over the config:

View File

@@ -32,6 +32,9 @@ svg-sprites [options] <config-file-or-directory>
| Environment | Mode |
|---|---|
| Static HTML / custom publishing | `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` |
@@ -45,7 +48,7 @@ When a directory is passed, all settings come from CLI options. When a config fi
Available options are `--mode`, `--name`, `--description`, `--input-folder`, repeatable `--input-file`, plus the `--remove-size`/`--no-remove-size`, `--replace-colors`/`--no-replace-colors`, `--add-transition`/`--no-add-transition`, and `--generated-notice`/`--no-generated-notice` pairs. Transform flags override individual fields, while supplying at least one `--input-file` replaces the complete config `inputFiles` array.
The mode must match the application's bundler. The generator creates different SVG asset integration code for Vite and for bundlers compatible with Webpack Asset Modules.
The mode must match the application's publishing strategy. Bare `standalone` leaves the public URL to the application; Vite and Webpack modes generate bundler-specific SVG asset integration.
## Unified configuration
@@ -105,7 +108,7 @@ Identical absolute paths are deduplicated. Different SVG files with the same fil
## Generated module
After generation, the sprite directory looks like this:
After generation, a React or Next.js sprite directory looks like this:
```text
app-icons/
@@ -140,6 +143,19 @@ app-icons/
| `.svg-sprite/*.d.ts` | TypeScript declarations for the corresponding JavaScript modules |
| `.svg-sprite/state.json` | Mode, contract version, and managed file list |
Standalone contracts do not create `react/`. Bare `standalone` contains only the
runtime asset and deployment-neutral manifest data:
```text
.svg-sprite/
├── state.json
├── sprite.svg
└── svg-sprite.manifest.json
```
`standalone@vite` and `standalone@webpack` additionally create `index.*`,
`icon-data.*`, and a resolved `svg-sprite.manifest.*`.
The generator overwrites and deletes only files that contain its marker. If a user file occupies a managed path, generation fails. The root `index.ts` is user-owned; create a barrel when needed:
```ts
@@ -235,7 +251,7 @@ For multiple sprites, add a separate CLI command for each directory or combine t
## Formats and rendering methods
React and Next.js modes generate the `stack` format.
All current modes generate the `stack` format.
| Format | `<svg><use>` | `<img>` | CSS background |
|---|---:|---:|---:|
@@ -253,6 +269,17 @@ For React and Next.js, use the generated component. It knows the internal IDs, c
How you obtain `spriteUrl` depends on the bundler.
Static HTML after the application publishes `.svg-sprite/sprite.svg`:
```html
<svg aria-hidden="true">
<use href="/assets/icons.svg#search"></use>
</svg>
```
Standalone Vite/Webpack provides generated `getIconsIconHref()` and an internal ID
map. Do not construct fragments from unsafe file names manually.
Vite:
```ts
@@ -306,12 +333,15 @@ The path in CSS is resolved relative to the CSS file itself. In these examples,
## Assets and caching
The generated component passes the SVG to the bundler as a separate asset:
The generated component or standalone facade passes the SVG to the bundler as a separate asset:
- Vite uses a static import with `?no-inline`;
- Webpack 5, Turbopack, and Next.js use `new URL(..., import.meta.url)`;
- SVG path data is not serialized into generated JavaScript.
Bare `standalone` does not participate in an asset pipeline: the application copies
or publishes `sprite.svg` and owns its URL, versioning, and cache policy.
With standard asset naming, the bundler adds a content hash:
```text
@@ -401,7 +431,7 @@ For a complex icon, you can disable `replaceColors` in a separate sprite configu
import { SpriteViewer } from '@gromlab/svg-sprites/react'
```
It accepts ready-made manifests, an array of lazy loaders, or a record in the format returned by `import.meta.glob`.
It accepts ready-made React/Next manifests, an array of lazy loaders, or a record in the format returned by `import.meta.glob`. The current Viewer does not load standalone manifests; standalone will use a separate viewer contract.
Vite:
@@ -488,6 +518,7 @@ If the sprite directory already contains a user-created `.gitignore` or a user-o
- `Refusing to overwrite a user file`: a file without the generated marker occupies a managed path.
- The icon does not change color: use `<svg><use>` or the generated component and check `replaceColors`.
- Webpack emits an incorrect URL: check Asset Modules, `output.publicPath`, and SVG loaders.
- Static sprite returns 404: check the post-generation copy or server alias, and do not put a filesystem `spritePath` into HTML.
- The Viewer cannot find the sprite: check the path to `.svg-sprite/svg-sprite.manifest.js` and run generation before starting the application.
- Build and mode do not match: use the target that corresponds to the actual bundler.

View File

@@ -14,6 +14,21 @@ const result = await generateSprite(
)
```
Для static standalone mode `result.spritePath` можно использовать в build-скрипте,
чтобы опубликовать SVG по URL приложения:
```ts
import { copyFile } from 'node:fs/promises'
const result = await generateSprite('src/sprite/svg-sprite.config.ts', {
mode: 'standalone',
})
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-модуля становится этот каталог.
Второй аргумент содержит необязательные overrides и всегда имеет приоритет над конфигом:

View File

@@ -32,6 +32,9 @@ svg-sprites [options] <config-file-or-directory>
| Среда | Mode |
|---|---|
| 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` |
@@ -45,7 +48,7 @@ Config-файл может иметь любое имя и расширение
Доступны `--mode`, `--name`, `--description`, `--input-folder`, повторяемый `--input-file`, а также пары `--remove-size`/`--no-remove-size`, `--replace-colors`/`--no-replace-colors`, `--add-transition`/`--no-add-transition` и `--generated-notice`/`--no-generated-notice`. Переданные transform-флаги перекрывают отдельные поля, а хотя бы один `--input-file` заменяет весь массив `inputFiles` из config.
Mode должен соответствовать сборщику приложения. Генератор создаёт разный способ подключения SVG asset для Vite и сборщиков, совместимых с Webpack Asset Modules.
Mode должен соответствовать способу публикации приложения. Bare `standalone` оставляет публичный URL приложению; Vite и Webpack modes генерируют bundler-specific подключение SVG asset.
## Единая конфигурация
@@ -105,7 +108,7 @@ file-manager → FileManagerIcon
## Generated-модуль
После генерации каталог спрайта выглядит так:
После генерации React- или Next.js-каталог спрайта выглядит так:
```text
app-icons/
@@ -140,6 +143,19 @@ app-icons/
| `.svg-sprite/*.d.ts` | TypeScript-декларации соответствующих JS-модулей |
| `.svg-sprite/state.json` | Mode, версия контракта и список управляемых файлов |
Standalone-контракты не создают каталог `react/`. Bare `standalone` содержит только
runtime asset и deployment-neutral manifest data:
```text
.svg-sprite/
├── state.json
├── sprite.svg
└── svg-sprite.manifest.json
```
`standalone@vite` и `standalone@webpack` дополнительно создают `index.*`,
`icon-data.*` и resolved `svg-sprite.manifest.*`.
Генератор перезаписывает и удаляет только файлы со своим marker. Если в managed-пути находится пользовательский файл, генерация завершается ошибкой. Корневой `index.ts` генератору не принадлежит; при необходимости создайте пользовательский barrel:
```ts
@@ -235,7 +251,7 @@ editor-icons → EditorIcon → иконки редактора
## Форматы и способы отображения
React- и Next.js-режимы создают формат `stack`.
Все текущие modes создают формат `stack`.
| Формат | `<svg><use>` | `<img>` | CSS background |
|---|---:|---:|---:|
@@ -253,6 +269,17 @@ React- и Next.js-режимы создают формат `stack`.
Способ получения `spriteUrl` зависит от сборщика.
Static HTML после публикации `.svg-sprite/sprite.svg` приложением:
```html
<svg aria-hidden="true">
<use href="/assets/icons.svg#search"></use>
</svg>
```
Standalone Vite/Webpack предоставляет generated `getIconsIconHref()` и mapping
внутренних IDs. Не конструируйте fragment из небезопасного имени файла вручную.
Vite:
```ts
@@ -306,12 +333,15 @@ Mask не сохраняет исходные цвета, gradients и разл
## Assets и кеширование
Generated-компонент передаёт SVG сборщику как отдельный asset:
Generated component или standalone facade передаёт SVG сборщику как отдельный asset:
- Vite использует статический импорт с `?no-inline`;
- Webpack 5, Turbopack и Next.js используют `new URL(..., import.meta.url)`;
- SVG path-данные не сериализуются в generated JavaScript.
Bare `standalone` не участвует в asset pipeline: приложение само копирует или
публикует `sprite.svg` и отвечает за URL, версионирование и cache policy.
При стандартном именовании assets сборщик добавляет content hash:
```text
@@ -401,7 +431,7 @@ fill="var(--icon-color-3, #129d9d)"
import { SpriteViewer } from '@gromlab/svg-sprites/react'
```
Он принимает готовые manifests, массив lazy loaders или record формата `import.meta.glob`.
Он принимает готовые React/Next manifests, массив lazy loaders или record формата `import.meta.glob`. Текущий Viewer не загружает standalone manifests; для standalone будет отдельный viewer-контракт.
Vite:
@@ -488,6 +518,7 @@ CI должен устанавливать development dependencies и выпо
- `Refusing to overwrite a user file`: в managed-пути находится файл без generated marker.
- Иконка не меняет цвет: используйте `<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` и выполните генерацию до запуска приложения.
- Build и mode не совпадают: используйте target, соответствующий фактическому сборщику.