mirror of
https://github.com/gromlab-ru/svg-sprites.git
synced 2026-07-22 04:40:17 +03:00
docs: обновить документацию generated-контракта
- описаны единая конфигурация и exact modes - обновлена структура .svg-sprite - удалены материалы legacy pipeline - синхронизированы русская и английская версии skill
This commit is contained in:
@@ -42,9 +42,9 @@
|
|||||||
|
|
||||||
`SpriteViewer` рендерит все спрайты проекта в одном месте и показывает, какие иконки вошли в каждый набор и как они выглядят. Для каждой иконки видны созданные CSS-переменные и их fallback-цвета. Значения можно менять прямо в Viewer и сразу наблюдать результат. Здесь же доступны готовые примеры подключения через React, `<svg><use>`, `<img>` и CSS.
|
`SpriteViewer` рендерит все спрайты проекта в одном месте и показывает, какие иконки вошли в каждый набор и как они выглядят. Для каждой иконки видны созданные CSS-переменные и их fallback-цвета. Значения можно менять прямо в Viewer и сразу наблюдать результат. Здесь же доступны готовые примеры подключения через React, `<svg><use>`, `<img>` и CSS.
|
||||||
|
|
||||||
11. **От нативного HTML до Next.js**
|
11. **React и Next.js**
|
||||||
|
|
||||||
В основе остаётся обычный SVG-спрайт, который можно использовать даже без фреймворка и сборщика. Для React и Next.js пакет генерирует типизированные компоненты и поддерживает Vite, Webpack 5 и Turbopack. Список готовых интеграций будет расширяться новыми фреймворками.
|
Пакет генерирует типизированные React-компоненты и поддерживает Vite, Webpack 5, Next.js App Router и Pages Router с Turbopack или Webpack.
|
||||||
|
|
||||||
12. **Чистый Git**
|
12. **Чистый Git**
|
||||||
|
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
`@gromlab/svg-sprites` is an SVG sprite generator for modern web applications. It combines selected SVG icons into one or more external, cacheable sprites and prepares them for use in the UI.
|
`@gromlab/svg-sprites` is an SVG sprite generator for modern web applications. It combines selected SVG icons into one or more external, cacheable sprites and prepares them for use in the UI.
|
||||||
|
|
||||||
For React and Next.js, the package generates typed components and supports Vite, Webpack 5, and Turbopack. At its core is a standard SVG sprite that can be used without a framework, including in native HTML.
|
For React and Next.js, the package generates typed components and external SVG assets with support for Vite, Webpack 5, and Turbopack.
|
||||||
|
|
||||||
## An SVG sprite as simple as a regular SVG icon
|
## An SVG sprite as simple as a regular SVG icon
|
||||||
|
|
||||||
@@ -61,9 +61,10 @@ Create the sprite configuration:
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/app-icons/svg-sprite.config.ts
|
// src/ui/app-icons/svg-sprite.config.ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'app',
|
name: 'app',
|
||||||
inputFiles: [
|
inputFiles: [
|
||||||
'../../assets/icons/search.svg',
|
'../../assets/icons/search.svg',
|
||||||
@@ -78,7 +79,7 @@ export default defineNextSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
"sprites": "svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprites",
|
"predev": "npm run sprites",
|
||||||
"prebuild": "npm run sprites"
|
"prebuild": "npm run sprites"
|
||||||
}
|
}
|
||||||
@@ -224,11 +225,9 @@ It also provides ready-to-use integration examples for:
|
|||||||
|
|
||||||
The Viewer is added only to an internal debug page and does not become part of the generated icon components.
|
The Viewer is added only to an internal debug page and does not become part of the generated icon components.
|
||||||
|
|
||||||
## From native HTML to Next.js
|
## React and Next.js
|
||||||
|
|
||||||
At its core is a standard SVG sprite that can be used even without a framework or bundler.
|
The package generates typed React components and supports Vite, Webpack 5, Next.js App Router, and Pages Router with Turbopack or Webpack.
|
||||||
|
|
||||||
For React and Next.js, the package generates typed components and supports Vite, Webpack 5, and Turbopack. The list of ready-made integrations will expand to include new frameworks.
|
|
||||||
|
|
||||||
## Clean Git history
|
## Clean Git history
|
||||||
|
|
||||||
@@ -252,13 +251,11 @@ This README introduces the project's capabilities and demonstrates the primary u
|
|||||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
- [React + Vite](docs/en/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Native HTML and classic SVG sprites](docs/en/legacy.md)
|
|
||||||
|
|
||||||
### Technical resources
|
### Technical resources
|
||||||
|
|
||||||
- [Technical reference](docs/en/reference.md)
|
- [Technical reference](docs/en/reference.md)
|
||||||
- [Programmatic API](docs/en/programmatic-api.md)
|
- [Programmatic API](docs/en/programmatic-api.md)
|
||||||
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
17
README_RU.md
17
README_RU.md
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
`@gromlab/svg-sprites` — генератор SVG-спрайтов для современных веб-приложений. Он собирает выбранные SVG-иконки в один или несколько внешних кешируемых спрайтов и подготавливает их для использования в интерфейсе.
|
`@gromlab/svg-sprites` — генератор SVG-спрайтов для современных веб-приложений. Он собирает выбранные SVG-иконки в один или несколько внешних кешируемых спрайтов и подготавливает их для использования в интерфейсе.
|
||||||
|
|
||||||
Для React и Next.js пакет создаёт типизированные компоненты и поддерживает Vite, Webpack 5 и Turbopack. В основе при этом остаётся обычный SVG-спрайт, который можно использовать без фреймворка, в том числе в нативном HTML.
|
Для React и Next.js пакет создаёт типизированные компоненты и внешние SVG assets, поддерживая Vite, Webpack 5 и Turbopack.
|
||||||
|
|
||||||
## SVG-спрайт так же прост, как обычная SVG-иконка
|
## SVG-спрайт так же прост, как обычная SVG-иконка
|
||||||
|
|
||||||
@@ -61,9 +61,10 @@ src/
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/app-icons/svg-sprite.config.ts
|
// src/ui/app-icons/svg-sprite.config.ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'app',
|
name: 'app',
|
||||||
inputFiles: [
|
inputFiles: [
|
||||||
'../../assets/icons/search.svg',
|
'../../assets/icons/search.svg',
|
||||||
@@ -78,7 +79,7 @@ export default defineNextSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
"sprites": "svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprites",
|
"predev": "npm run sprites",
|
||||||
"prebuild": "npm run sprites"
|
"prebuild": "npm run sprites"
|
||||||
}
|
}
|
||||||
@@ -224,11 +225,9 @@ JavaScript отвечает за интерфейс и поведение, а г
|
|||||||
|
|
||||||
Viewer подключается только к внутренней debug-странице и не становится частью generated-компонентов иконок.
|
Viewer подключается только к внутренней debug-странице и не становится частью generated-компонентов иконок.
|
||||||
|
|
||||||
## От нативного HTML до Next.js
|
## React и Next.js
|
||||||
|
|
||||||
В основе остаётся обычный SVG-спрайт, который можно использовать даже без фреймворка и сборщика.
|
Пакет генерирует типизированные React-компоненты и поддерживает Vite, Webpack 5, Next.js App Router и Pages Router с Turbopack или Webpack.
|
||||||
|
|
||||||
Для React и Next.js пакет генерирует типизированные компоненты и поддерживает Vite, Webpack 5 и Turbopack. Список готовых интеграций будет расширяться новыми фреймворками.
|
|
||||||
|
|
||||||
## Чистый Git
|
## Чистый Git
|
||||||
|
|
||||||
@@ -252,13 +251,11 @@ README знакомит с возможностями проекта и пока
|
|||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||||
- [React + Vite](docs/ru/react-vite.md)
|
- [React + Vite](docs/ru/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||||
- [Нативный HTML и классические SVG-спрайты](docs/ru/legacy.md)
|
|
||||||
|
|
||||||
### Технические материалы
|
### Технические материалы
|
||||||
|
|
||||||
- [Технический справочник](docs/ru/reference.md)
|
- [Технический справочник](docs/ru/reference.md)
|
||||||
- [Программный API](docs/ru/programmatic-api.md)
|
- [Программный API](docs/ru/programmatic-api.md)
|
||||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
|
||||||
|
|
||||||
## Лицензия
|
## Лицензия
|
||||||
|
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
# Legacy mode
|
|
||||||
|
|
||||||
[← Back to home](../../README.md)
|
|
||||||
|
|
||||||
A quick guide to generating centralized SVG sprites in `symbol` and `stack` formats, with an optional HTML preview.
|
|
||||||
|
|
||||||
## 1. Install the package
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. Prepare the icons and config
|
|
||||||
|
|
||||||
```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. Add generation
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy .",
|
|
||||||
"prebuild": "npm run sprites"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the local package through the script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Result:
|
|
||||||
|
|
||||||
```text
|
|
||||||
public/sprites/
|
|
||||||
├── icons.sprite.svg
|
|
||||||
└── preview.html
|
|
||||||
```
|
|
||||||
|
|
||||||
With `preview: false`, the HTML file is not created. For the `stack` format, specify `format: 'stack'`.
|
|
||||||
|
|
||||||
## 4. Use the symbol sprite
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg width="24" height="24" aria-label="Done">
|
|
||||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
|
||||||
</svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Multiple sprites
|
|
||||||
|
|
||||||
Add multiple entries to `sprites`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'logos',
|
|
||||||
input: 'src/assets/logos',
|
|
||||||
format: 'stack',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
All output files and the shared `preview.html` will be written to `output`.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
- Config not found: make sure `svg-sprites.config.ts` is located in the specified root directory.
|
|
||||||
- No icons: check `sprites[].input` and the `.svg` extension.
|
|
||||||
- Preview not needed: set `preview: false`.
|
|
||||||
|
|
||||||
For programmatic use, see [`generateLegacy`](programmatic-api.md#generatelegacy).
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
# Migrating from 0.1.x to 1.0
|
|
||||||
|
|
||||||
[← Back to home](../../README.md)
|
|
||||||
|
|
||||||
Version 1.0 separates local generation for React and Next.js from the centralized legacy mode. The old config cannot be mixed with the new API in a single CLI invocation.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Install the package as a development dependency so the migration uses the version recorded in the project lockfile:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
## CLI
|
|
||||||
|
|
||||||
The CLI now always requires an explicit `--mode` and a path to the configuration directory:
|
|
||||||
|
|
||||||
```text
|
|
||||||
"sprites": "svg-sprites"
|
|
||||||
→ "sprites": "svg-sprites --mode <mode> <path>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Choose a mode based on your environment:
|
|
||||||
|
|
||||||
| Environment | 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` |
|
|
||||||
| Centralized legacy setup | `legacy` |
|
|
||||||
|
|
||||||
## React and Next.js
|
|
||||||
|
|
||||||
Instead of a root-level `svg-sprites.config.ts`, create a local `svg-sprite.config.ts` next to the icon set:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
|
||||||
name: 'global',
|
|
||||||
inputFolder: './icons',
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
For regular React, use `defineReactSpriteConfig`. A folder and an explicit list of shared SVG files can be combined using `inputFolder` and `inputFiles`.
|
|
||||||
|
|
||||||
Add the local CLI with the selected mode to `package.json`, for example:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprite:global": "svg-sprites --mode next@app/turbopack src/ui/global/svg-sprite"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Run it with `npm run sprite:global` before importing the generated component.
|
|
||||||
|
|
||||||
The old `publicPath` and `react` options are no longer needed. The generated module is created next to the config and adds its own `.gitignore`, while Vite, Webpack, or Next.js emits the SVG as a separate asset with a content hash.
|
|
||||||
|
|
||||||
The `<SvgSprite icon="..." />` component is replaced by a component whose name is derived from `name`:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
<GlobalIcon icon="check" />
|
|
||||||
```
|
|
||||||
|
|
||||||
To browse the icons, add `<SpriteViewer>` as a debug page in the application. A separate `preview.html` is available only in legacy mode.
|
|
||||||
|
|
||||||
## Legacy mode
|
|
||||||
|
|
||||||
If you need to preserve the centralized structure, rename the helper and the format fields:
|
|
||||||
|
|
||||||
```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` has been replaced with `defineLegacyConfig`;
|
|
||||||
- `sprites[].mode` has been renamed to `sprites[].format`;
|
|
||||||
- `generate` has been replaced with `generateLegacy`;
|
|
||||||
- `loadConfig` has been replaced with `loadLegacyConfig`;
|
|
||||||
- `publicPath` and generation of the old shared React component have been removed.
|
|
||||||
|
|
||||||
Add the local CLI to `package.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy ."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Run it with `npm run sprites`.
|
|
||||||
|
|
||||||
## Programmatic API
|
|
||||||
|
|
||||||
The package is distributed as ESM only. Replace `require()` with `import`.
|
|
||||||
|
|
||||||
`compileSpriteContent` now returns `Promise<Uint8Array>` so that the public declarations do not require `@types/node` to be installed. In Node.js, the actual result is compatible with APIs that accept `Uint8Array`.
|
|
||||||
|
|
||||||
## After migration
|
|
||||||
|
|
||||||
1. Add an explicit generation command before `dev`, `build`, and `typecheck`.
|
|
||||||
2. Generate the new output and run type checking while the old artifacts are still available.
|
|
||||||
3. Replace imports and verify the icons and color variables using `SpriteViewer` or the legacy `preview.html`.
|
|
||||||
4. Only then remove confirmed old generated files and obsolete ignore rules without deleting source SVGs.
|
|
||||||
@@ -22,19 +22,28 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The root barrel is application-owned:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
## 3. Add generation
|
## 3. Add generation
|
||||||
|
|
||||||
For Turbopack:
|
For Turbopack:
|
||||||
@@ -42,7 +51,7 @@ For Turbopack:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager"
|
"prebuild": "npm run sprite:file-manager"
|
||||||
}
|
}
|
||||||
@@ -85,7 +94,7 @@ The viewer is interactive, so it requires a separate Client Component boundary:
|
|||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
() => import('@/ui/file-manager/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function SpritesPage() {
|
export default function SpritesPage() {
|
||||||
|
|||||||
@@ -22,25 +22,34 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@pages/webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The root barrel is application-owned:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
## 3. Add generation
|
## 3. Add generation
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager"
|
"prebuild": "npm run sprite:file-manager"
|
||||||
}
|
}
|
||||||
@@ -77,7 +86,7 @@ The component works the same way with SSR, SSG, and client-side navigation. Next
|
|||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
() => import('@/ui/file-manager/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function SpritesPage() {
|
export default function SpritesPage() {
|
||||||
|
|||||||
@@ -2,100 +2,65 @@
|
|||||||
|
|
||||||
[← Back to home](../../README.md)
|
[← Back to home](../../README.md)
|
||||||
|
|
||||||
The package provides a main Node.js entry point and a separate React runtime entry point. Both are distributed as ESM only and must be loaded with `import`.
|
The package is ESM-only and provides one Node.js generation API. The React runtime with `SpriteViewer` is available from the separate `@gromlab/svg-sprites/react` entry point.
|
||||||
|
|
||||||
To resolve `@gromlab/svg-sprites/react` in TypeScript, use `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
## `generateSprite`
|
||||||
|
|
||||||
## Main entry point
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {
|
import { generateSprite } from '@gromlab/svg-sprites'
|
||||||
defineNextSpriteConfig,
|
|
||||||
defineReactSpriteConfig,
|
|
||||||
generateNextSprite,
|
|
||||||
generateReactSprite,
|
|
||||||
} from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
The main entry point does not import React and can be used in CLIs, build scripts, and Node.js tools.
|
const result = await generateSprite(
|
||||||
|
'src/ui/file-manager/svg-sprite/svg-sprite.config.ts',
|
||||||
## `generateReactSprite`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const result = await generateReactSprite(
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
'vite',
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
The second argument is required:
|
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:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type ReactAssetTarget = 'vite' | 'webpack'
|
await generateSprite('src/ui/file-manager/svg-sprite/custom-config.json', {
|
||||||
```
|
mode: 'react@webpack',
|
||||||
|
name: 'documents',
|
||||||
Result:
|
inputFolder: './assets',
|
||||||
|
inputFiles: ['../../shared/search.svg'],
|
||||||
```ts
|
transform: {
|
||||||
type ReactSpriteGenerationResult = {
|
addTransition: false,
|
||||||
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)
|
|
||||||
```
|
|
||||||
|
|
||||||
The function loads `svg-sprite.config.ts` from the specified root, compiles the SVG files, and safely updates managed files.
|
|
||||||
|
|
||||||
## `generateNextSprite`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { generateNextSprite } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const result = await generateNextSprite(
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
{
|
|
||||||
router: 'app',
|
|
||||||
bundler: 'turbopack',
|
|
||||||
},
|
},
|
||||||
)
|
generatedNotice: false,
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Available values:
|
Configuration is resolved in this order:
|
||||||
|
|
||||||
```ts
|
```text
|
||||||
type NextSpriteGenerationOptions = {
|
defaults → config → API overrides
|
||||||
router: 'app' | 'pages'
|
|
||||||
bundler: 'turbopack' | 'webpack'
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The result also contains the selected `router`, `bundler`, and the full target in the form `next@app/turbopack`.
|
For fully programmatic generation, pass a directory and provide the required settings as overrides:
|
||||||
|
|
||||||
## `defineReactSpriteConfig`
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
await generateSprite('src/ui/file-manager/svg-sprite', {
|
||||||
|
mode: 'react@vite',
|
||||||
|
name: 'file-manager',
|
||||||
|
inputFiles: [
|
||||||
|
'../../shared/search.svg',
|
||||||
|
'../../shared/settings.svg',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
## Configuration
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
inputFiles: [
|
inputFiles: ['../../shared/check.svg'],
|
||||||
'../../shared/icons/check.svg',
|
|
||||||
],
|
|
||||||
transform: {
|
transform: {
|
||||||
removeSize: true,
|
removeSize: true,
|
||||||
replaceColors: true,
|
replaceColors: true,
|
||||||
@@ -105,99 +70,54 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
`inputFolder` and `inputFiles` are combined. The helper returns the configuration without runtime transformations and provides TypeScript autocomplete.
|
`defineSpriteConfig` is an identity helper for TypeScript autocomplete. JavaScript can export the same object with `export default`, while JSON contains the object directly.
|
||||||
|
|
||||||
## `defineNextSpriteConfig`
|
## Specialized wrappers
|
||||||
|
|
||||||
|
The specialized functions are available as wrappers around `generateSprite`:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { generateNextSprite, generateReactSprite } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
await generateReactSprite('path/to/config.ts', 'vite')
|
||||||
name: 'file-manager',
|
await generateNextSprite('path/to/config.ts', {
|
||||||
description: 'File manager icons',
|
router: 'app',
|
||||||
inputFolder: './icons',
|
bundler: 'turbopack',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Next.js uses the same configuration contract as the React presets.
|
An explicitly supplied target overrides `mode` from the file. Prefer `generateSprite` in new code.
|
||||||
|
|
||||||
## `generateLegacy`
|
## Config API
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { generateLegacy } from '@gromlab/svg-sprites'
|
import {
|
||||||
|
loadSpriteConfig,
|
||||||
const results = await generateLegacy({
|
resolveSpriteConfig,
|
||||||
output: 'public/sprites',
|
validateSpriteConfig,
|
||||||
preview: false,
|
} from '@gromlab/svg-sprites'
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns an array:
|
- `loadSpriteConfig(file)` loads an explicitly selected `.ts`, `.js`, or `.json` file.
|
||||||
|
- `validateSpriteConfig(value)` performs runtime validation.
|
||||||
|
- `resolveSpriteConfig(root, config, overrides)` merges values, applies defaults, and resolves paths relative to `root`.
|
||||||
|
|
||||||
```ts
|
## Low-level compiler
|
||||||
type SpriteResult = {
|
|
||||||
name: string
|
|
||||||
format: 'symbol' | 'stack'
|
|
||||||
spritePath: string
|
|
||||||
iconCount: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For details, see [Legacy mode](legacy.md).
|
|
||||||
|
|
||||||
## Low-level functions
|
|
||||||
|
|
||||||
The main entry point also exports:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {
|
import {
|
||||||
compileSprite,
|
compileSprite,
|
||||||
compileSpriteContent,
|
compileSpriteContent,
|
||||||
createShapeTransform,
|
createShapeTransform,
|
||||||
generatePreview,
|
|
||||||
loadLegacyConfig,
|
|
||||||
loadReactSpriteConfig,
|
|
||||||
resolveSpriteEntry,
|
|
||||||
resolveSprites,
|
|
||||||
} from '@gromlab/svg-sprites'
|
} from '@gromlab/svg-sprites'
|
||||||
```
|
```
|
||||||
|
|
||||||
These functions are intended for custom orchestration built on top of the existing compiler and writer. For standard usage, prefer `generateReactSprite` and `generateLegacy`.
|
These functions are intended for custom orchestration. Standard generation should use `generateSprite`.
|
||||||
|
|
||||||
## React runtime entry point
|
## React runtime
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
```
|
```
|
||||||
|
|
||||||
Types:
|
`SpriteViewer` accepts generated manifests, lazy loaders, or an `import.meta.glob` result. This entry point contains `'use client'` and is intended for debug tools; production components are imported from local sprite modules.
|
||||||
|
|
||||||
```ts
|
|
||||||
import type {
|
|
||||||
SpriteManifest,
|
|
||||||
SpriteManifestColor,
|
|
||||||
SpriteManifestIcon,
|
|
||||||
SpriteManifestLoader,
|
|
||||||
SpriteManifestModule,
|
|
||||||
SpriteViewerColorTheme,
|
|
||||||
SpriteViewerProps,
|
|
||||||
SpriteViewerSource,
|
|
||||||
SpriteViewerSources,
|
|
||||||
} from '@gromlab/svg-sprites/react'
|
|
||||||
```
|
|
||||||
|
|
||||||
The React entry point contains `'use client'` and is intended for debug tools. Generated production components are imported from the application's local sprite modules, not from the package's React entry point.
|
|
||||||
|
|
||||||
`SpriteViewerProps.colorTheme` accepts `auto | light | dark`. The default is `auto`, which follows `prefers-color-scheme`; to synchronize it with the application theme, pass the computed `light` or `dark` value.
|
|
||||||
|
|
||||||
## Related guides
|
|
||||||
|
|
||||||
- [React + Vite](react-vite.md)
|
|
||||||
- [React + Webpack 5](react-webpack.md)
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -28,24 +29,32 @@ Place the source SVG files in `icons/`.
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The root barrel is application-owned and explicitly re-exports the generated API:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
By default, SVG files are loaded from `./icons`. You can add shared icons from other directories through `inputFiles`: the directory and file list are combined into a single sprite.
|
By default, SVG files are loaded from `./icons`. You can add shared icons from other directories through `inputFiles`: the directory and file list are combined into a single sprite.
|
||||||
|
|
||||||
The complete list of options is available under [React and Next.js configuration](reference.md#react-and-nextjs-configuration).
|
The complete list of options is available under [Unified configuration](reference.md#unified-configuration).
|
||||||
|
|
||||||
## 4. Add generation to package.json
|
## 4. Add generation to package.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -96,7 +105,7 @@ import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|||||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = import.meta.glob<SpriteManifestModule>(
|
const sources = import.meta.glob<SpriteManifestModule>(
|
||||||
'/src/**/svg-sprite/manifest.ts',
|
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -104,13 +113,13 @@ export const IconsDebugPage = () => (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Vite automatically finds the generated `manifest.ts` for each React sprite. The `import.meta.glob` pattern must be a string literal, and generation must run before Vite starts.
|
Vite automatically finds the generated manifest for each React sprite. The `import.meta.glob` pattern must be a string literal, and generation must run before Vite starts.
|
||||||
|
|
||||||
Only include the Viewer on a debug route or in an internal tool.
|
Only include the Viewer on a debug route or in an internal tool.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
- Missing `index.ts`: run `npm run sprite:file-manager`.
|
- Missing `.svg-sprite/index.js`: run `npm run sprite:file-manager`.
|
||||||
- The Viewer cannot find the sprite: check the glob path and make sure `manifest.ts` exists.
|
- The Viewer cannot find the sprite: check the glob path to `.svg-sprite/svg-sprite.manifest.js`.
|
||||||
- `Refusing to overwrite a user file` error: there is a user file at a generated path.
|
- `Refusing to overwrite a user file` error: there is a user file at a generated path.
|
||||||
- The icon does not change color: use `color` or `--icon-color-N`.
|
- The icon does not change color: use `color` or `--icon-color-N`.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -28,24 +29,32 @@ Place the source SVG files in `icons/`.
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The root barrel is application-owned and explicitly re-exports the generated API:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
By default, SVG files are loaded from `./icons`. You can add shared icons from other directories through `inputFiles`: the directory and file list are combined into a single sprite.
|
By default, SVG files are loaded from `./icons`. You can add shared icons from other directories through `inputFiles`: the directory and file list are combined into a single sprite.
|
||||||
|
|
||||||
The complete list of options is available under [React and Next.js configuration](reference.md#react-and-nextjs-configuration).
|
The complete list of options is available under [Unified configuration](reference.md#unified-configuration).
|
||||||
|
|
||||||
## 4. Add generation to package.json
|
## 4. Add generation to package.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -87,7 +96,7 @@ Webpack processes the generated `new URL('./sprite.svg', import.meta.url)` throu
|
|||||||
|
|
||||||
If the project already uses a custom SVG loader, make sure it does not intercept the generated `sprite.svg` instead of Asset Modules.
|
If the project already uses a custom SVG loader, make sure it does not intercept the generated `sprite.svg` instead of Asset Modules.
|
||||||
|
|
||||||
The generated component imports `styles.module.css`, so Webpack must process CSS Modules through `css-loader` and `style-loader` or `MiniCssExtractPlugin`. If the TypeScript project does not include a declaration for CSS Modules, add one separately.
|
The generated component imports `react/react-component.module.css`, so Webpack must process CSS Modules through `css-loader` and `style-loader` or `MiniCssExtractPlugin`. If the TypeScript project does not include a declaration for CSS Modules, add one separately.
|
||||||
|
|
||||||
## 6. Add a debug page
|
## 6. Add a debug page
|
||||||
|
|
||||||
@@ -97,8 +106,8 @@ Webpack does not support Vite's `import.meta.glob` API, so provide static loader
|
|||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('./ui/file-manager/svg-sprite/manifest'),
|
() => import('./ui/file-manager/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
() => import('./ui/navigation/svg-sprite/manifest'),
|
() => import('./ui/navigation/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -112,8 +121,8 @@ Only include the Viewer on a debug route or in an internal tool.
|
|||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
- Missing `index.ts`: run `npm run sprite:file-manager`.
|
- Missing `.svg-sprite/index.js`: run `npm run sprite:file-manager`.
|
||||||
- The Viewer does not load the sprite: check the path in `import()` and make sure `manifest.ts` exists.
|
- The Viewer does not load the sprite: check the `import()` path to `.svg-sprite/svg-sprite.manifest.js`.
|
||||||
- Incorrect asset URL: check `output.publicPath`.
|
- Incorrect asset URL: check `output.publicPath`.
|
||||||
- Another loader intercepts the SVG: exclude the generated sprite from the incompatible rule.
|
- Another loader intercepts the SVG: exclude the generated sprite from the incompatible rule.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ Reference for the configuration, generated API, and behavior of `@gromlab/svg-sp
|
|||||||
- [Next.js Pages Router](next-pages.md)
|
- [Next.js Pages Router](next-pages.md)
|
||||||
- [React + Vite](react-vite.md)
|
- [React + Vite](react-vite.md)
|
||||||
- [React + Webpack 5](react-webpack.md)
|
- [React + Webpack 5](react-webpack.md)
|
||||||
- [Native HTML and classic SVG sprites](legacy.md)
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -25,10 +24,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
|
|
||||||
## CLI and generation modes
|
## CLI and generation modes
|
||||||
|
|
||||||
The CLI accepts one mode and a path to the configuration directory:
|
The CLI accepts exactly one path: an explicitly selected config file or a directory for config-less generation:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
svg-sprites --mode <mode> <path>
|
svg-sprites [options] <config-file-or-directory>
|
||||||
```
|
```
|
||||||
|
|
||||||
| Environment | Mode |
|
| Environment | Mode |
|
||||||
@@ -39,20 +38,24 @@ svg-sprites --mode <mode> <path>
|
|||||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||||
| Classic `stack` and `symbol` sprites | `legacy` |
|
|
||||||
|
|
||||||
Modern React and Next.js modes use a local `svg-sprite.config.ts`. Legacy mode uses a separate `svg-sprites.config.ts` and is covered in [its own guide](legacy.md).
|
The config file may have any name and use the `.ts`, `.js`, or `.json` extension. The CLI does not discover it by convention: pass the file explicitly. The guides use `svg-sprite.config.ts` as the recommended name.
|
||||||
|
|
||||||
|
When a directory is passed, all settings come from CLI options. When a config file is passed, CLI options override the file. The full order is `defaults → config → CLI`.
|
||||||
|
|
||||||
|
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 bundler. The generator creates different SVG asset integration code for Vite and for bundlers compatible with Webpack Asset Modules.
|
||||||
|
|
||||||
## React and Next.js configuration
|
## Unified configuration
|
||||||
|
|
||||||
Each directory containing `svg-sprite.config.ts` defines one independent sprite.
|
Each config file defines one independent sprite.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'app',
|
name: 'app',
|
||||||
description: 'Shared application icons',
|
description: 'Shared application icons',
|
||||||
inputFolder: './local-icons',
|
inputFolder: './local-icons',
|
||||||
@@ -69,18 +72,13 @@ export default defineNextSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
For React, use `defineReactSpriteConfig`. The configuration contract is the same:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
| Option | Type | Default | Purpose |
|
| Option | Type | Default | Purpose |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|
| `mode` | `SpriteMode` | None | Generation mode; may be supplied by CLI/API |
|
||||||
| `name` | `string` | Derived from the directory | Name of the sprite, component, and public types |
|
| `name` | `string` | Derived from the directory | Name of the sprite, component, and public types |
|
||||||
| `description` | `string` | None | Description for types and the debug manifest |
|
| `description` | `string` | None | Description for types and the debug manifest |
|
||||||
| `inputFolder` | `string` | `./icons` | SVG directory relative to the configuration file |
|
| `inputFolder` | `string` | `./icons` | SVG directory relative to the module root |
|
||||||
| `inputFiles` | `string[]` | `[]` | Paths to individual SVG files relative to the configuration file |
|
| `inputFiles` | `string[]` | `[]` | Paths to individual SVG files relative to the module root |
|
||||||
| `transform` | `TransformOptions` | All enabled | SVG preparation settings |
|
| `transform` | `TransformOptions` | All enabled | SVG preparation settings |
|
||||||
| `generatedNotice` | `boolean` | `true` | Full or abbreviated warning in generated files |
|
| `generatedNotice` | `boolean` | `true` | Full or abbreviated warning in generated files |
|
||||||
|
|
||||||
@@ -112,28 +110,41 @@ After generation, the sprite directory looks like this:
|
|||||||
```text
|
```text
|
||||||
app-icons/
|
app-icons/
|
||||||
├── .gitignore
|
├── .gitignore
|
||||||
├── index.ts
|
|
||||||
├── manifest.ts
|
|
||||||
├── svg-sprite.config.ts
|
├── svg-sprite.config.ts
|
||||||
└── generated/
|
├── index.ts # optional user-owned barrel
|
||||||
├── .svg-sprites.manifest.json
|
└── .svg-sprite/
|
||||||
├── react-component.tsx
|
├── state.json
|
||||||
|
├── index.js
|
||||||
|
├── index.d.ts
|
||||||
|
├── icon-data.js
|
||||||
|
├── icon-data.d.ts
|
||||||
├── sprite.svg
|
├── sprite.svg
|
||||||
├── styles.module.css
|
├── svg-sprite.manifest.js
|
||||||
└── types.ts
|
├── svg-sprite.manifest.d.ts
|
||||||
|
└── react/
|
||||||
|
├── react-component.js
|
||||||
|
├── react-component.d.ts
|
||||||
|
└── react-component.module.css
|
||||||
```
|
```
|
||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `index.ts` | Production exports for the component, props, styles, and icon names |
|
| `.svg-sprite/index.js` | Production exports for the component and runtime icon-name list |
|
||||||
| `manifest.ts` | Debug metadata and the asset URL for `SpriteViewer` |
|
| `.svg-sprite/index.d.ts` | Public declarations for the component, props, styles, and icon-name union |
|
||||||
| `generated/sprite.svg` | Compiled SVG sprite |
|
| `.svg-sprite/svg-sprite.manifest.js` | Debug metadata and the asset URL for `SpriteViewer` |
|
||||||
| `generated/react-component.tsx` | Typed React component |
|
| `.svg-sprite/sprite.svg` | Compiled SVG sprite |
|
||||||
| `generated/styles.module.css` | Base styles and transitions |
|
| `.svg-sprite/react/react-component.js` | React component runtime without TypeScript or JSX |
|
||||||
| `generated/types.ts` | Runtime list and union type of icon names |
|
| `.svg-sprite/react/react-component.d.ts` | React component props, style, and declaration |
|
||||||
| `generated/.svg-sprites.manifest.json` | List of files managed by the generator |
|
| `.svg-sprite/react/react-component.module.css` | Styles for the React implementation |
|
||||||
|
| `.svg-sprite/icon-data.js` | Runtime icon-name list and internal IDs |
|
||||||
|
| `.svg-sprite/*.d.ts` | TypeScript declarations for the corresponding JavaScript modules |
|
||||||
|
| `.svg-sprite/state.json` | Mode, contract version, and managed file list |
|
||||||
|
|
||||||
The generator overwrites and deletes only files that contain its marker. If a user file occupies a managed path, generation fails.
|
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
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
## React component and TypeScript
|
## React component and TypeScript
|
||||||
|
|
||||||
@@ -224,12 +235,11 @@ For multiple sprites, add a separate CLI command for each directory or combine t
|
|||||||
|
|
||||||
## Formats and rendering methods
|
## Formats and rendering methods
|
||||||
|
|
||||||
Modern React and Next.js modes generate the `stack` format. Legacy mode supports both `stack` and `symbol`.
|
React and Next.js modes generate the `stack` format.
|
||||||
|
|
||||||
| Format | `<svg><use>` | `<img>` | CSS background |
|
| Format | `<svg><use>` | `<img>` | CSS background |
|
||||||
|---|---:|---:|---:|
|
|---|---:|---:|---:|
|
||||||
| `stack` | Yes | Yes | Yes |
|
| `stack` | Yes | Yes | Yes |
|
||||||
| `symbol` | Yes | No | No |
|
|
||||||
|
|
||||||
### Generated component
|
### Generated component
|
||||||
|
|
||||||
@@ -246,13 +256,13 @@ How you obtain `spriteUrl` depends on the bundler.
|
|||||||
Vite:
|
Vite:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import spriteUrl from './generated/sprite.svg?no-inline'
|
import spriteUrl from './.svg-sprite/sprite.svg?no-inline'
|
||||||
```
|
```
|
||||||
|
|
||||||
Webpack 5, Turbopack, and Next.js:
|
Webpack 5, Turbopack, and Next.js:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const spriteUrl = new URL('./generated/sprite.svg', import.meta.url).href
|
const spriteUrl = new URL('./.svg-sprite/sprite.svg', import.meta.url).href
|
||||||
```
|
```
|
||||||
|
|
||||||
After obtaining the URL, use it in JSX:
|
After obtaining the URL, use it in JSX:
|
||||||
@@ -277,7 +287,7 @@ An SVG inside `<img>` is isolated from the page's CSS. Setting `color` or `--ico
|
|||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
background: url('./generated/sprite.svg#search') center / contain no-repeat;
|
background: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -286,7 +296,7 @@ For a single-color silhouette, you can use a mask:
|
|||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
mask: url('./generated/sprite.svg#search') center / contain no-repeat;
|
mask: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -300,7 +310,7 @@ The generated component passes the SVG to the bundler as a separate asset:
|
|||||||
|
|
||||||
- Vite uses a static import with `?no-inline`;
|
- Vite uses a static import with `?no-inline`;
|
||||||
- Webpack 5, Turbopack, and Next.js use `new URL(..., import.meta.url)`;
|
- Webpack 5, Turbopack, and Next.js use `new URL(..., import.meta.url)`;
|
||||||
- SVG path data is not serialized into the generated TSX.
|
- SVG path data is not serialized into generated JavaScript.
|
||||||
|
|
||||||
With standard asset naming, the bundler adds a content hash:
|
With standard asset naming, the bundler adds a content hash:
|
||||||
|
|
||||||
@@ -325,7 +335,8 @@ All transformations are enabled by default and can be configured independently:
|
|||||||
To disable an individual operation:
|
To disable an individual operation:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
transform: {
|
transform: {
|
||||||
removeSize: false,
|
removeSize: false,
|
||||||
replaceColors: false,
|
replaceColors: false,
|
||||||
@@ -399,7 +410,7 @@ import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|||||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = import.meta.glob<SpriteManifestModule>(
|
const sources = import.meta.glob<SpriteManifestModule>(
|
||||||
'/src/**/svg-sprite/manifest.ts',
|
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -411,8 +422,8 @@ Webpack and Next.js:
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('@/ui/app-icons/manifest'),
|
() => import('@/ui/app-icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
() => import('@/features/analytics/icons/manifest'),
|
() => import('@/features/analytics/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -447,9 +458,7 @@ To synchronize it with the application theme:
|
|||||||
A modern sprite module creates a local `.gitignore` for:
|
A modern sprite module creates a local `.gitignore` for:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/generated/
|
/.svg-sprite/
|
||||||
/index.ts
|
|
||||||
/manifest.ts
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Commit the local `.gitignore` to the repository once. It excludes the other generated files, so generation must run before commands that import the sprite module:
|
Commit the local `.gitignore` to the repository once. It excludes the other generated files, so generation must run before commands that import the sprite module:
|
||||||
@@ -457,7 +466,7 @@ Commit the local `.gitignore` to the repository once. It excludes the other gene
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
"sprites": "svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprites",
|
"predev": "npm run sprites",
|
||||||
"prebuild": "npm run sprites",
|
"prebuild": "npm run sprites",
|
||||||
"pretypecheck": "npm run sprites"
|
"pretypecheck": "npm run sprites"
|
||||||
@@ -467,18 +476,19 @@ Commit the local `.gitignore` to the repository once. It excludes the other gene
|
|||||||
|
|
||||||
CI must install development dependencies and run the generation script before building or type-checking.
|
CI must install development dependencies and run the generation script before building or type-checking.
|
||||||
|
|
||||||
If the sprite directory already contains a user-created `.gitignore`, `index.ts`, or `manifest.ts`, the generator will not overwrite it. Move the user file or choose a separate sprite directory.
|
If the sprite directory already contains a user-created `.gitignore` or a user-owned file inside `.svg-sprite`, the generator will not overwrite it. The root `index.ts` remains user-owned and may re-export the generated API.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
- Missing `index.ts`: run the generation script before importing the module.
|
- Missing `.svg-sprite/index.js`: run the generation script before importing the generated module.
|
||||||
- Configuration not found: check the CLI path and the `svg-sprite.config.ts` file name.
|
- Source not found: pass an existing config file or sprite module directory.
|
||||||
|
- Mode missing: add `mode` to the config or pass `--mode`.
|
||||||
- Icon missing from the type: check `inputFiles`, the `.svg` extension, and the nesting level under `inputFolder`.
|
- Icon missing from the type: check `inputFiles`, the `.svg` extension, and the nesting level under `inputFolder`.
|
||||||
- Name conflict: two different SVG files have the same basename; rename one of them.
|
- Name conflict: two different SVG files have the same basename; rename one of them.
|
||||||
- `Refusing to overwrite a user file`: a file without the generated marker occupies a managed path.
|
- `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`.
|
- 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.
|
- Webpack emits an incorrect URL: check Asset Modules, `output.publicPath`, and SVG loaders.
|
||||||
- The Viewer cannot find the sprite: check the path to `manifest.ts` and run generation before starting the application.
|
- 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.
|
- Build and mode do not match: use the target that corresponds to the actual bundler.
|
||||||
|
|
||||||
For custom orchestration and low-level compilation, see the [Programmatic API](programmatic-api.md).
|
For custom orchestration and low-level compilation, see the [Programmatic API](programmatic-api.md).
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
# Legacy mode
|
|
||||||
|
|
||||||
[← Главная](../../README_RU.md)
|
|
||||||
|
|
||||||
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
|
|
||||||
|
|
||||||
## 1. Установите пакет
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @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. Добавьте генерацию
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy .",
|
|
||||||
"prebuild": "npm run sprites"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Запустите локально установленный пакет через script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Результат:
|
|
||||||
|
|
||||||
```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>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Несколько спрайтов
|
|
||||||
|
|
||||||
Добавьте несколько записей в `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).
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
# Миграция с 0.1.x на 1.0
|
|
||||||
|
|
||||||
[← Главная](../../README_RU.md)
|
|
||||||
|
|
||||||
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
|
|
||||||
Установите пакет как development dependency, чтобы миграция использовала версию из lockfile проекта:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
## CLI
|
|
||||||
|
|
||||||
CLI теперь всегда требует явный `--mode` и путь к каталогу конфигурации:
|
|
||||||
|
|
||||||
```text
|
|
||||||
"sprites": "svg-sprites"
|
|
||||||
→ "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`.
|
|
||||||
|
|
||||||
Добавьте локальный CLI с выбранным mode в `package.json`, например:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprite:global": "svg-sprites --mode next@app/turbopack src/ui/global/svg-sprite"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Запустите его командой `npm run sprite:global` до импорта generated-компонента.
|
|
||||||
|
|
||||||
Старые `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-компонента удалены.
|
|
||||||
|
|
||||||
Добавьте локальный CLI в `package.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy ."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Запустите его командой `npm run sprites`.
|
|
||||||
|
|
||||||
## Программный API
|
|
||||||
|
|
||||||
Пакет распространяется только как ESM. Замените `require()` на `import`.
|
|
||||||
|
|
||||||
`compileSpriteContent` теперь возвращает `Promise<Uint8Array>`, чтобы публичные декларации не требовали установки `@types/node`. В Node.js фактический результат совместим с API, принимающими `Uint8Array`.
|
|
||||||
|
|
||||||
## После миграции
|
|
||||||
|
|
||||||
1. Добавьте явную команду генерации перед `dev`, `build` и `typecheck`.
|
|
||||||
2. Создайте новый output и запустите проверку типов, пока старые artifacts остаются доступны.
|
|
||||||
3. Замените imports и проверьте иконки и цветовые переменные через `SpriteViewer` или legacy `preview.html`.
|
|
||||||
4. Только после этого удалите подтверждённые старые generated-файлы и устаревшие ignore rules, не затрагивая исходные SVG.
|
|
||||||
@@ -22,19 +22,28 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Корневой barrel принадлежит приложению:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
## 3. Добавьте генерацию
|
## 3. Добавьте генерацию
|
||||||
|
|
||||||
Для Turbopack:
|
Для Turbopack:
|
||||||
@@ -42,7 +51,7 @@ export default defineNextSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager"
|
"prebuild": "npm run sprite:file-manager"
|
||||||
}
|
}
|
||||||
@@ -85,7 +94,7 @@ Viewer интерактивен, поэтому для него нужна от
|
|||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
() => import('@/ui/file-manager/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function SpritesPage() {
|
export default function SpritesPage() {
|
||||||
|
|||||||
@@ -22,25 +22,34 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@pages/webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Корневой barrel принадлежит приложению:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
## 3. Добавьте генерацию
|
## 3. Добавьте генерацию
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager"
|
"prebuild": "npm run sprite:file-manager"
|
||||||
}
|
}
|
||||||
@@ -77,7 +86,7 @@ export function getServerSideProps() {
|
|||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
() => import('@/ui/file-manager/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function SpritesPage() {
|
export default function SpritesPage() {
|
||||||
|
|||||||
@@ -2,100 +2,65 @@
|
|||||||
|
|
||||||
[← Главная](../../README_RU.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
|
Пакет распространяется как ESM и предоставляет единый Node.js API генерации. React runtime с `SpriteViewer` находится в отдельной точке входа `@gromlab/svg-sprites/react`.
|
||||||
|
|
||||||
Для разрешения `@gromlab/svg-sprites/react` в TypeScript используйте `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
## `generateSprite`
|
||||||
|
|
||||||
## Основной entry
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {
|
import { generateSprite } from '@gromlab/svg-sprites'
|
||||||
defineNextSpriteConfig,
|
|
||||||
defineReactSpriteConfig,
|
|
||||||
generateNextSprite,
|
|
||||||
generateReactSprite,
|
|
||||||
} from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
Основной entry не импортирует React и может использоваться в CLI, build scripts и Node.js инструментах.
|
const result = await generateSprite(
|
||||||
|
'src/ui/file-manager/svg-sprite/svg-sprite.config.ts',
|
||||||
## `generateReactSprite`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const result = await generateReactSprite(
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
'vite',
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Второй аргумент обязателен:
|
Первый аргумент принимает полный путь к config-файлу с любым именем и расширением `.ts`, `.js` или `.json`. Каталог вместо файла включает config-less режим: корнем sprite-модуля становится этот каталог.
|
||||||
|
|
||||||
|
Второй аргумент содержит необязательные overrides и всегда имеет приоритет над конфигом:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type ReactAssetTarget = 'vite' | 'webpack'
|
await generateSprite('src/ui/file-manager/svg-sprite/custom-config.json', {
|
||||||
```
|
mode: 'react@webpack',
|
||||||
|
name: 'documents',
|
||||||
Результат:
|
inputFolder: './assets',
|
||||||
|
inputFiles: ['../../shared/search.svg'],
|
||||||
```ts
|
transform: {
|
||||||
type ReactSpriteGenerationResult = {
|
addTransition: false,
|
||||||
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',
|
|
||||||
},
|
},
|
||||||
)
|
generatedNotice: false,
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Доступные значения:
|
Порядок разрешения настроек:
|
||||||
|
|
||||||
```ts
|
```text
|
||||||
type NextSpriteGenerationOptions = {
|
defaults → config → API overrides
|
||||||
router: 'app' | 'pages'
|
|
||||||
bundler: 'turbopack' | 'webpack'
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Результат дополнительно содержит выбранные `router`, `bundler` и полный target вида `next@app/turbopack`.
|
Для полностью программной генерации передайте каталог и все обязательные настройки через overrides:
|
||||||
|
|
||||||
## `defineReactSpriteConfig`
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
await generateSprite('src/ui/file-manager/svg-sprite', {
|
||||||
|
mode: 'react@vite',
|
||||||
|
name: 'file-manager',
|
||||||
|
inputFiles: [
|
||||||
|
'../../shared/search.svg',
|
||||||
|
'../../shared/settings.svg',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
## Конфигурация
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
inputFiles: [
|
inputFiles: ['../../shared/check.svg'],
|
||||||
'../../shared/icons/check.svg',
|
|
||||||
],
|
|
||||||
transform: {
|
transform: {
|
||||||
removeSize: true,
|
removeSize: true,
|
||||||
replaceColors: true,
|
replaceColors: true,
|
||||||
@@ -105,99 +70,54 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
`inputFolder` и `inputFiles` объединяются. Хелпер возвращает конфиг без runtime-преобразований и предоставляет TypeScript autocomplete.
|
`defineSpriteConfig` является identity helper для TypeScript autocomplete. JS может экспортировать тот же объект через `export default`, а JSON содержит объект непосредственно.
|
||||||
|
|
||||||
## `defineNextSpriteConfig`
|
## Специализированные обёртки
|
||||||
|
|
||||||
|
Специализированные функции доступны как обёртки над `generateSprite`:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { generateNextSprite, generateReactSprite } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
await generateReactSprite('path/to/config.ts', 'vite')
|
||||||
name: 'file-manager',
|
await generateNextSprite('path/to/config.ts', {
|
||||||
description: 'Иконки файлового менеджера',
|
router: 'app',
|
||||||
inputFolder: './icons',
|
bundler: 'turbopack',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Next.js использует тот же контракт конфигурации, что и React presets.
|
Явно переданный target перекрывает `mode` из файла. Для нового кода используйте `generateSprite`.
|
||||||
|
|
||||||
## `generateLegacy`
|
## Config API
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { generateLegacy } from '@gromlab/svg-sprites'
|
import {
|
||||||
|
loadSpriteConfig,
|
||||||
const results = await generateLegacy({
|
resolveSpriteConfig,
|
||||||
output: 'public/sprites',
|
validateSpriteConfig,
|
||||||
preview: false,
|
} from '@gromlab/svg-sprites'
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращается массив:
|
- `loadSpriteConfig(file)` загружает явно указанный `.ts`, `.js` или `.json` файл.
|
||||||
|
- `validateSpriteConfig(value)` выполняет runtime-валидацию объекта.
|
||||||
|
- `resolveSpriteConfig(root, config, overrides)` объединяет значения, добавляет defaults и разрешает пути относительно `root`.
|
||||||
|
|
||||||
```ts
|
## Низкоуровневый compiler
|
||||||
type SpriteResult = {
|
|
||||||
name: string
|
|
||||||
format: 'symbol' | 'stack'
|
|
||||||
spritePath: string
|
|
||||||
iconCount: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Подробнее: [Legacy mode](legacy.md).
|
|
||||||
|
|
||||||
## Низкоуровневые функции
|
|
||||||
|
|
||||||
Основная точка входа также экспортирует:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import {
|
import {
|
||||||
compileSprite,
|
compileSprite,
|
||||||
compileSpriteContent,
|
compileSpriteContent,
|
||||||
createShapeTransform,
|
createShapeTransform,
|
||||||
generatePreview,
|
|
||||||
loadLegacyConfig,
|
|
||||||
loadReactSpriteConfig,
|
|
||||||
resolveSpriteEntry,
|
|
||||||
resolveSprites,
|
|
||||||
} from '@gromlab/svg-sprites'
|
} from '@gromlab/svg-sprites'
|
||||||
```
|
```
|
||||||
|
|
||||||
Эти функции предназначены для собственного orchestration поверх существующего compiler и writer. Для стандартного использования предпочтительны `generateReactSprite` и `generateLegacy`.
|
Эти функции предназначены для собственного orchestration. Стандартная генерация должна выполняться через `generateSprite`.
|
||||||
|
|
||||||
## React runtime entry
|
## React runtime
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
```
|
```
|
||||||
|
|
||||||
Типы:
|
`SpriteViewer` принимает generated manifests, lazy loaders или результат `import.meta.glob`. Эта точка входа содержит `'use client'` и предназначена для debug-инструментов; production-компоненты импортируются из локальных sprite-модулей приложения.
|
||||||
|
|
||||||
```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)
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -28,24 +29,32 @@ src/ui/file-manager/svg-sprite/
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Корневой barrel принадлежит приложению и явно возвращает generated API:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||||
|
|
||||||
Полный список опций находится в разделе [«Конфигурация React и Next.js»](reference.md#конфигурация-react-и-nextjs).
|
Полный список опций находится в разделе [«Единая конфигурация»](reference.md#единая-конфигурация).
|
||||||
|
|
||||||
## 4. Добавьте генерацию в package.json
|
## 4. Добавьте генерацию в package.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -96,7 +105,7 @@ import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|||||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = import.meta.glob<SpriteManifestModule>(
|
const sources = import.meta.glob<SpriteManifestModule>(
|
||||||
'/src/**/svg-sprite/manifest.ts',
|
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -104,13 +113,13 @@ export const IconsDebugPage = () => (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Vite автоматически найдёт generated `manifest.ts` каждого React-спрайта. Шаблон `import.meta.glob` должен быть строковым литералом, а генерация должна выполниться до запуска Vite.
|
Vite автоматически найдёт generated manifest каждого React-спрайта. Шаблон `import.meta.glob` должен быть строковым литералом, а генерация должна выполниться до запуска Vite.
|
||||||
|
|
||||||
Размещайте Viewer только на debug-маршруте или во внутреннем инструменте.
|
Размещайте Viewer только на debug-маршруте или во внутреннем инструменте.
|
||||||
|
|
||||||
## Если что-то не работает
|
## Если что-то не работает
|
||||||
|
|
||||||
- Нет `index.ts`: запустите `npm run sprite:file-manager`.
|
- Нет `.svg-sprite/index.js`: запустите `npm run sprite:file-manager`.
|
||||||
- Viewer не видит спрайт: проверьте путь glob и наличие `manifest.ts`.
|
- Viewer не видит спрайт: проверьте glob-путь к `.svg-sprite/svg-sprite.manifest.js`.
|
||||||
- Ошибка `Refusing to overwrite a user file`: в generated-пути находится пользовательский файл.
|
- Ошибка `Refusing to overwrite a user file`: в generated-пути находится пользовательский файл.
|
||||||
- Иконка не меняет цвет: используйте `color` или `--icon-color-N`.
|
- Иконка не меняет цвет: используйте `color` или `--icon-color-N`.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ src/ui/file-manager/svg-sprite/
|
|||||||
├── icons/
|
├── icons/
|
||||||
│ ├── check.svg
|
│ ├── check.svg
|
||||||
│ └── folder.svg
|
│ └── folder.svg
|
||||||
|
├── index.ts
|
||||||
└── svg-sprite.config.ts
|
└── svg-sprite.config.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -28,24 +29,32 @@ src/ui/file-manager/svg-sprite/
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Корневой barrel принадлежит приложению и явно возвращает generated API:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/ui/file-manager/svg-sprite/index.ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||||
|
|
||||||
Полный список опций находится в разделе [«Конфигурация React и Next.js»](reference.md#конфигурация-react-и-nextjs).
|
Полный список опций находится в разделе [«Единая конфигурация»](reference.md#единая-конфигурация).
|
||||||
|
|
||||||
## 4. Добавьте генерацию в package.json
|
## 4. Добавьте генерацию в package.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -87,7 +96,7 @@ Webpack обработает generated `new URL('./sprite.svg', import.meta.url)
|
|||||||
|
|
||||||
Если проект уже использует собственный SVG loader, убедитесь, что он не перехватывает generated `sprite.svg` вместо Asset Modules.
|
Если проект уже использует собственный SVG loader, убедитесь, что он не перехватывает generated `sprite.svg` вместо Asset Modules.
|
||||||
|
|
||||||
Generated-компонент импортирует `styles.module.css`, поэтому Webpack должен обрабатывать CSS Modules через `css-loader` и `style-loader` либо `MiniCssExtractPlugin`. Если TypeScript-проект не содержит декларации для CSS Modules, добавьте её отдельно.
|
Generated-компонент импортирует `react/react-component.module.css`, поэтому Webpack должен обрабатывать CSS Modules через `css-loader` и `style-loader` либо `MiniCssExtractPlugin`. Если TypeScript-проект не содержит декларации для CSS Modules, добавьте её отдельно.
|
||||||
|
|
||||||
## 6. Добавьте debug-страницу
|
## 6. Добавьте debug-страницу
|
||||||
|
|
||||||
@@ -97,8 +106,8 @@ Webpack не поддерживает Vite API `import.meta.glob`, поэтом
|
|||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('./ui/file-manager/svg-sprite/manifest'),
|
() => import('./ui/file-manager/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
() => import('./ui/navigation/svg-sprite/manifest'),
|
() => import('./ui/navigation/svg-sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -112,8 +121,8 @@ export const IconsDebugPage = () => (
|
|||||||
|
|
||||||
## Если что-то не работает
|
## Если что-то не работает
|
||||||
|
|
||||||
- Нет `index.ts`: запустите `npm run sprite:file-manager`.
|
- Нет `.svg-sprite/index.js`: запустите `npm run sprite:file-manager`.
|
||||||
- Viewer не загружает спрайт: проверьте путь в `import()` и наличие `manifest.ts`.
|
- Viewer не загружает спрайт: проверьте путь в `import()` к `.svg-sprite/svg-sprite.manifest.js`.
|
||||||
- Неверный URL asset: проверьте `output.publicPath`.
|
- Неверный URL asset: проверьте `output.publicPath`.
|
||||||
- SVG перехватывает другой loader: исключите generated sprite из несовместимого правила.
|
- SVG перехватывает другой loader: исключите generated sprite из несовместимого правила.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
- [Next.js Pages Router](next-pages.md)
|
- [Next.js Pages Router](next-pages.md)
|
||||||
- [React + Vite](react-vite.md)
|
- [React + Vite](react-vite.md)
|
||||||
- [React + Webpack 5](react-webpack.md)
|
- [React + Webpack 5](react-webpack.md)
|
||||||
- [Нативный HTML и классические SVG-спрайты](legacy.md)
|
|
||||||
|
|
||||||
## Требования
|
## Требования
|
||||||
|
|
||||||
@@ -25,10 +24,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
|
|
||||||
## CLI и режимы генерации
|
## CLI и режимы генерации
|
||||||
|
|
||||||
CLI принимает один режим и путь к каталогу конфигурации:
|
CLI принимает ровно один путь: явно выбранный config-файл либо каталог для config-less генерации:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
svg-sprites --mode <mode> <path>
|
svg-sprites [options] <config-file-or-directory>
|
||||||
```
|
```
|
||||||
|
|
||||||
| Среда | Mode |
|
| Среда | Mode |
|
||||||
@@ -39,20 +38,24 @@ svg-sprites --mode <mode> <path>
|
|||||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||||
| Классические `stack`- и `symbol`-спрайты | `legacy` |
|
|
||||||
|
|
||||||
Современные React- и Next.js-режимы используют локальный `svg-sprite.config.ts`. Legacy-режим использует отдельный `svg-sprites.config.ts` и описан в [собственном руководстве](legacy.md).
|
Config-файл может иметь любое имя и расширение `.ts`, `.js` или `.json`. CLI не ищет конфиг по соглашению: файл нужно передать явно. В руководствах используется рекомендуемое имя `svg-sprite.config.ts`.
|
||||||
|
|
||||||
|
Если передан каталог, все настройки берутся из CLI. Если передан config-файл, CLI-параметры перекрывают значения файла. Общий порядок: `defaults → config → CLI`.
|
||||||
|
|
||||||
|
Доступны `--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 должен соответствовать сборщику приложения. Генератор создаёт разный способ подключения SVG asset для Vite и сборщиков, совместимых с Webpack Asset Modules.
|
||||||
|
|
||||||
## Конфигурация React и Next.js
|
## Единая конфигурация
|
||||||
|
|
||||||
Каждый каталог с `svg-sprite.config.ts` описывает один независимый спрайт.
|
Каждый config-файл описывает один независимый спрайт.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'app',
|
name: 'app',
|
||||||
description: 'Общие иконки приложения',
|
description: 'Общие иконки приложения',
|
||||||
inputFolder: './local-icons',
|
inputFolder: './local-icons',
|
||||||
@@ -69,18 +72,13 @@ export default defineNextSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Для React используйте `defineReactSpriteConfig`. Контракт конфигурации одинаковый:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
| Опция | Тип | По умолчанию | Назначение |
|
| Опция | Тип | По умолчанию | Назначение |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|
| `mode` | `SpriteMode` | Нет | Режим генерации; можно передать через CLI/API |
|
||||||
| `name` | `string` | Выводится из каталога | Имя спрайта, компонента и публичных типов |
|
| `name` | `string` | Выводится из каталога | Имя спрайта, компонента и публичных типов |
|
||||||
| `description` | `string` | Нет | Описание для типов и debug manifest |
|
| `description` | `string` | Нет | Описание для типов и debug manifest |
|
||||||
| `inputFolder` | `string` | `./icons` | Каталог с SVG относительно конфига |
|
| `inputFolder` | `string` | `./icons` | Каталог с SVG относительно корня модуля |
|
||||||
| `inputFiles` | `string[]` | `[]` | Пути к отдельным SVG относительно конфига |
|
| `inputFiles` | `string[]` | `[]` | Пути к отдельным SVG относительно корня модуля |
|
||||||
| `transform` | `TransformOptions` | Все включены | Настройки подготовки SVG |
|
| `transform` | `TransformOptions` | Все включены | Настройки подготовки SVG |
|
||||||
| `generatedNotice` | `boolean` | `true` | Полное или короткое предупреждение в generated-файлах |
|
| `generatedNotice` | `boolean` | `true` | Полное или короткое предупреждение в generated-файлах |
|
||||||
|
|
||||||
@@ -112,28 +110,41 @@ file-manager → FileManagerIcon
|
|||||||
```text
|
```text
|
||||||
app-icons/
|
app-icons/
|
||||||
├── .gitignore
|
├── .gitignore
|
||||||
├── index.ts
|
|
||||||
├── manifest.ts
|
|
||||||
├── svg-sprite.config.ts
|
├── svg-sprite.config.ts
|
||||||
└── generated/
|
├── index.ts # необязательный пользовательский barrel
|
||||||
├── .svg-sprites.manifest.json
|
└── .svg-sprite/
|
||||||
├── react-component.tsx
|
├── state.json
|
||||||
|
├── index.js
|
||||||
|
├── index.d.ts
|
||||||
|
├── icon-data.js
|
||||||
|
├── icon-data.d.ts
|
||||||
├── sprite.svg
|
├── sprite.svg
|
||||||
├── styles.module.css
|
├── svg-sprite.manifest.js
|
||||||
└── types.ts
|
├── svg-sprite.manifest.d.ts
|
||||||
|
└── react/
|
||||||
|
├── react-component.js
|
||||||
|
├── react-component.d.ts
|
||||||
|
└── react-component.module.css
|
||||||
```
|
```
|
||||||
|
|
||||||
| Файл | Назначение |
|
| Файл | Назначение |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `index.ts` | Production exports компонента, props, стилей и имён иконок |
|
| `.svg-sprite/index.js` | Production exports компонента и runtime-списка имён |
|
||||||
| `manifest.ts` | Debug metadata и URL asset для `SpriteViewer` |
|
| `.svg-sprite/index.d.ts` | Публичные декларации компонента, props, стилей и union-типа имён |
|
||||||
| `generated/sprite.svg` | Собранный SVG-спрайт |
|
| `.svg-sprite/svg-sprite.manifest.js` | Debug metadata и URL asset для `SpriteViewer` |
|
||||||
| `generated/react-component.tsx` | Типизированный React-компонент |
|
| `.svg-sprite/sprite.svg` | Собранный SVG-спрайт |
|
||||||
| `generated/styles.module.css` | Базовые стили и transitions |
|
| `.svg-sprite/react/react-component.js` | Runtime React-компонента без TypeScript и JSX |
|
||||||
| `generated/types.ts` | Runtime-список и union-тип имён |
|
| `.svg-sprite/react/react-component.d.ts` | Props, style и declaration React-компонента |
|
||||||
| `generated/.svg-sprites.manifest.json` | Список файлов, которыми управляет генератор |
|
| `.svg-sprite/react/react-component.module.css` | Стили конкретной React-реализации |
|
||||||
|
| `.svg-sprite/icon-data.js` | Runtime-список имён и внутренние IDs |
|
||||||
|
| `.svg-sprite/*.d.ts` | TypeScript-декларации соответствующих JS-модулей |
|
||||||
|
| `.svg-sprite/state.json` | Mode, версия контракта и список управляемых файлов |
|
||||||
|
|
||||||
Генератор перезаписывает и удаляет только файлы со своим marker. Если в managed-пути находится пользовательский файл, генерация завершается ошибкой.
|
Генератор перезаписывает и удаляет только файлы со своим marker. Если в managed-пути находится пользовательский файл, генерация завершается ошибкой. Корневой `index.ts` генератору не принадлежит; при необходимости создайте пользовательский barrel:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
## React-компонент и TypeScript
|
## React-компонент и TypeScript
|
||||||
|
|
||||||
@@ -224,12 +235,11 @@ editor-icons → EditorIcon → иконки редактора
|
|||||||
|
|
||||||
## Форматы и способы отображения
|
## Форматы и способы отображения
|
||||||
|
|
||||||
Современные React- и Next.js-режимы создают формат `stack`. Legacy-режим поддерживает `stack` и `symbol`.
|
React- и Next.js-режимы создают формат `stack`.
|
||||||
|
|
||||||
| Формат | `<svg><use>` | `<img>` | CSS background |
|
| Формат | `<svg><use>` | `<img>` | CSS background |
|
||||||
|---|---:|---:|---:|
|
|---|---:|---:|---:|
|
||||||
| `stack` | Да | Да | Да |
|
| `stack` | Да | Да | Да |
|
||||||
| `symbol` | Да | Нет | Нет |
|
|
||||||
|
|
||||||
### Generated-компонент
|
### Generated-компонент
|
||||||
|
|
||||||
@@ -246,13 +256,13 @@ editor-icons → EditorIcon → иконки редактора
|
|||||||
Vite:
|
Vite:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import spriteUrl from './generated/sprite.svg?no-inline'
|
import spriteUrl from './.svg-sprite/sprite.svg?no-inline'
|
||||||
```
|
```
|
||||||
|
|
||||||
Webpack 5, Turbopack и Next.js:
|
Webpack 5, Turbopack и Next.js:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const spriteUrl = new URL('./generated/sprite.svg', import.meta.url).href
|
const spriteUrl = new URL('./.svg-sprite/sprite.svg', import.meta.url).href
|
||||||
```
|
```
|
||||||
|
|
||||||
После получения URL используйте его в JSX:
|
После получения URL используйте его в JSX:
|
||||||
@@ -277,7 +287,7 @@ SVG внутри `<img>` изолирован от CSS страницы. `color`
|
|||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
background: url('./generated/sprite.svg#search') center / contain no-repeat;
|
background: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -286,7 +296,7 @@ SVG внутри `<img>` изолирован от CSS страницы. `color`
|
|||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
mask: url('./generated/sprite.svg#search') center / contain no-repeat;
|
mask: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -300,7 +310,7 @@ Generated-компонент передаёт SVG сборщику как отд
|
|||||||
|
|
||||||
- Vite использует статический импорт с `?no-inline`;
|
- Vite использует статический импорт с `?no-inline`;
|
||||||
- Webpack 5, Turbopack и Next.js используют `new URL(..., import.meta.url)`;
|
- Webpack 5, Turbopack и Next.js используют `new URL(..., import.meta.url)`;
|
||||||
- SVG path-данные не сериализуются в generated TSX.
|
- SVG path-данные не сериализуются в generated JavaScript.
|
||||||
|
|
||||||
При стандартном именовании assets сборщик добавляет content hash:
|
При стандартном именовании assets сборщик добавляет content hash:
|
||||||
|
|
||||||
@@ -325,7 +335,8 @@ HTTP cache headers, CDN и `Cache-Control` настраиваются прило
|
|||||||
Чтобы отключить отдельную операцию:
|
Чтобы отключить отдельную операцию:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
transform: {
|
transform: {
|
||||||
removeSize: false,
|
removeSize: false,
|
||||||
replaceColors: false,
|
replaceColors: false,
|
||||||
@@ -399,7 +410,7 @@ import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|||||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = import.meta.glob<SpriteManifestModule>(
|
const sources = import.meta.glob<SpriteManifestModule>(
|
||||||
'/src/**/svg-sprite/manifest.ts',
|
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -411,8 +422,8 @@ Webpack и Next.js:
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const sources = [
|
const sources = [
|
||||||
() => import('@/ui/app-icons/manifest'),
|
() => import('@/ui/app-icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
() => import('@/features/analytics/icons/manifest'),
|
() => import('@/features/analytics/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||||
]
|
]
|
||||||
|
|
||||||
export const IconsDebugPage = () => (
|
export const IconsDebugPage = () => (
|
||||||
@@ -447,9 +458,7 @@ Viewer показывает группы, поиск, `viewBox`, CSS-перем
|
|||||||
Современный sprite-модуль создаёт локальный `.gitignore` для:
|
Современный sprite-модуль создаёт локальный `.gitignore` для:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/generated/
|
/.svg-sprite/
|
||||||
/index.ts
|
|
||||||
/manifest.ts
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Локальный `.gitignore` следует один раз добавить в репозиторий. Он исключает остальные generated-файлы, поэтому генерацию нужно запускать перед командами, которые импортируют sprite-модуль:
|
Локальный `.gitignore` следует один раз добавить в репозиторий. Он исключает остальные generated-файлы, поэтому генерацию нужно запускать перед командами, которые импортируют sprite-модуль:
|
||||||
@@ -457,7 +466,7 @@ Viewer показывает группы, поиск, `viewBox`, CSS-перем
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
"sprites": "svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprites",
|
"predev": "npm run sprites",
|
||||||
"prebuild": "npm run sprites",
|
"prebuild": "npm run sprites",
|
||||||
"pretypecheck": "npm run sprites"
|
"pretypecheck": "npm run sprites"
|
||||||
@@ -467,18 +476,19 @@ Viewer показывает группы, поиск, `viewBox`, CSS-перем
|
|||||||
|
|
||||||
CI должен устанавливать development dependencies и выполнять generation script до сборки или проверки типов.
|
CI должен устанавливать development dependencies и выполнять generation script до сборки или проверки типов.
|
||||||
|
|
||||||
Если в каталоге спрайта уже находится пользовательский `.gitignore`, `index.ts` или `manifest.ts`, генератор не перезапишет его. Переместите пользовательский файл или выберите отдельный каталог спрайта.
|
Если в каталоге спрайта уже находится пользовательский `.gitignore` либо пользовательский файл внутри `.svg-sprite`, генератор не перезапишет его. Корневой `index.ts` остаётся пользовательским и может переэкспортировать generated API.
|
||||||
|
|
||||||
## Диагностика
|
## Диагностика
|
||||||
|
|
||||||
- Нет `index.ts`: запустите generation script до импорта модуля.
|
- Нет `.svg-sprite/index.js`: запустите generation script до импорта generated-модуля.
|
||||||
- Не найдена конфигурация: проверьте путь CLI и имя `svg-sprite.config.ts`.
|
- Не найден источник: передайте существующий config-файл или каталог sprite-модуля.
|
||||||
|
- Не указан mode: добавьте `mode` в config либо передайте `--mode`.
|
||||||
- Иконка отсутствует в типе: проверьте `inputFiles`, расширение `.svg` и уровень вложенности `inputFolder`.
|
- Иконка отсутствует в типе: проверьте `inputFiles`, расширение `.svg` и уровень вложенности `inputFolder`.
|
||||||
- Конфликт имени: два разных SVG имеют одинаковый basename; переименуйте один файл.
|
- Конфликт имени: два разных SVG имеют одинаковый basename; переименуйте один файл.
|
||||||
- `Refusing to overwrite a user file`: в managed-пути находится файл без generated marker.
|
- `Refusing to overwrite a user file`: в managed-пути находится файл без generated marker.
|
||||||
- Иконка не меняет цвет: используйте `<svg><use>` или generated-компонент и проверьте `replaceColors`.
|
- Иконка не меняет цвет: используйте `<svg><use>` или generated-компонент и проверьте `replaceColors`.
|
||||||
- Webpack выдаёт неверный URL: проверьте Asset Modules, `output.publicPath` и SVG loaders.
|
- Webpack выдаёт неверный URL: проверьте Asset Modules, `output.publicPath` и SVG loaders.
|
||||||
- Viewer не видит спрайт: проверьте путь к `manifest.ts` и выполните генерацию до запуска приложения.
|
- Viewer не видит спрайт: проверьте путь к `.svg-sprite/svg-sprite.manifest.js` и выполните генерацию до запуска приложения.
|
||||||
- Build и mode не совпадают: используйте target, соответствующий фактическому сборщику.
|
- Build и mode не совпадают: используйте target, соответствующий фактическому сборщику.
|
||||||
|
|
||||||
Для собственного orchestration и низкоуровневой компиляции смотрите [Программный API](programmatic-api.md).
|
Для собственного orchestration и низкоуровневой компиляции смотрите [Программный API](programmatic-api.md).
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ src/<language>/
|
|||||||
├── react-webpack.md
|
├── react-webpack.md
|
||||||
├── next-app.md
|
├── next-app.md
|
||||||
├── next-pages.md
|
├── next-pages.md
|
||||||
├── legacy.md
|
|
||||||
├── migration-1.md
|
|
||||||
├── programmatic-api.md
|
├── programmatic-api.md
|
||||||
└── complex-svg.md
|
└── complex-svg.md
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ const agentReferences = [
|
|||||||
'react-webpack.md',
|
'react-webpack.md',
|
||||||
'next-app.md',
|
'next-app.md',
|
||||||
'next-pages.md',
|
'next-pages.md',
|
||||||
'legacy.md',
|
|
||||||
'migration-1.md',
|
|
||||||
'programmatic-api.md',
|
'programmatic-api.md',
|
||||||
'complex-svg.md',
|
'complex-svg.md',
|
||||||
]
|
]
|
||||||
@@ -37,7 +35,7 @@ const upstream = [
|
|||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name: 'svg-sprites',
|
name: 'svg-sprites',
|
||||||
description: 'Use only when configuring, generating, migrating, or troubleshooting @gromlab/svg-sprites. Triggers: @gromlab/svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, defineLegacyConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, 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.ts, defineSpriteConfig, generateSprite, react@vite, react@webpack, next@app, next@pages, inputFiles, 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',
|
output: '../artifacts/svg-sprites',
|
||||||
maxSkillBytes: 48_000,
|
maxSkillBytes: 48_000,
|
||||||
documents: documents('en'),
|
documents: documents('en'),
|
||||||
@@ -45,7 +43,7 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'svg-sprites-ru',
|
name: 'svg-sprites-ru',
|
||||||
description: 'Используй только при настройке, изменении, миграции или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, defineLegacyConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
|
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.ts, defineSpriteConfig, generateSprite, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
|
||||||
output: '../artifacts/svg-sprites-ru',
|
output: '../artifacts/svg-sprites-ru',
|
||||||
maxSkillBytes: 48_000,
|
maxSkillBytes: 48_000,
|
||||||
documents: documents('ru'),
|
documents: documents('ru'),
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
- For React + Vite, open [React + Vite](./references/react-vite.md); for React with a custom Webpack 5 setup, open [React + Webpack](./references/react-webpack.md).
|
- For React + Vite, open [React + Vite](./references/react-vite.md); for React with a custom Webpack 5 setup, open [React + Webpack](./references/react-webpack.md).
|
||||||
- For Next.js, open the guide for the [App Router](./references/next-app.md) or [Pages Router](./references/next-pages.md), then select the section for the bundler actually in use.
|
- For Next.js, open the guide for the [App Router](./references/next-app.md) or [Pages Router](./references/next-pages.md), then select the section for the bundler actually in use.
|
||||||
- If the project has `svg-sprites.config.ts`, open [legacy mode](./references/legacy.md); when upgrading from `0.1.x`, also open the [migration guide](./references/migration-1.md).
|
|
||||||
- To invoke the generator from Node.js, open the [programmatic API](./references/programmatic-api.md).
|
- To invoke the generator from Node.js, open the [programmatic API](./references/programmatic-api.md).
|
||||||
- For gradients, filters, `url(#...)`, unusual colors, and `viewBox` issues, open [complex SVGs](./references/complex-svg.md).
|
- For gradients, filters, `url(#...)`, unusual colors, and `viewBox` issues, open [complex SVGs](./references/complex-svg.md).
|
||||||
- Use the complete user documentation as a secondary source: [package README](./references/upstream/README.md).
|
- Use the complete user documentation as a secondary source: [package README](./references/upstream/README.md).
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
`@gromlab/svg-sprites` is a CLI generator that builds SVG sprites from user-provided SVG files. The package does not include its own icon set: it compiles the project's SVGs into an external cacheable sprite asset and, for React/Next.js, creates a typed component, a list of valid names, and a debug manifest.
|
`@gromlab/svg-sprites` is a CLI generator that builds SVG sprites from user-provided SVG files. The package does not include its own icon set: it compiles the project's SVGs into an external cacheable sprite asset and, for React/Next.js, creates a typed component, a list of valid names, and a debug manifest.
|
||||||
|
|
||||||
The package supports multiple independent sprites in one project. Each selected directory containing `svg-sprite.config.ts` describes one sprite and gets its own:
|
The package supports multiple independent sprites in one project. Each explicitly selected config file or config-less directory describes one sprite and gets its own:
|
||||||
|
|
||||||
- SVG asset;
|
- SVG asset;
|
||||||
- icon name types;
|
- icon name types;
|
||||||
- React component;
|
- React component;
|
||||||
- production entry point `index.ts`;
|
- production entry point `.svg-sprite/index.js` with `.d.ts`;
|
||||||
- debug entry point `manifest.ts`.
|
- debug entry point `.svg-sprite/svg-sprite.manifest.js` with `.d.ts`.
|
||||||
|
|
||||||
The project determines how many sprite directories exist and where they live. For example, `name: 'file-manager'` produces `FileManagerIcon`, while another directory with `name: 'navigation'` produces a separate `NavigationIcon`. The names `FileManagerIcon` and `fileManagerIconNames` used below are examples of the API for one possible sprite, not fixed package exports.
|
The project determines how many sprite directories exist and where they live. For example, `name: 'file-manager'` produces `FileManagerIcon`, while another directory with `name: 'navigation'` produces a separate `NavigationIcon`. The names `FileManagerIcon` and `fileManagerIconNames` used below are examples of the API for one possible sprite, not fixed package exports.
|
||||||
|
|
||||||
|
|||||||
@@ -10,24 +10,18 @@ Select exactly one supported mode key:
|
|||||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||||
| Existing shared config | `legacy` |
|
|
||||||
|
|
||||||
Do not use the incomplete `react`, `next@app`, or `next@pages` keys, the future `standalone` mode, or a mode for a different bundler. Install the package as a development dependency and add the local CLI to a package script. The CLI always requires a mode and exactly one path to a configuration directory:
|
Mode may come from the config, CLI, or programmatic API. Values are applied as `defaults → config → CLI/API overrides`. A mode must exist after merging.
|
||||||
|
|
||||||
|
The CLI accepts exactly one path. A `.ts`, `.js`, or `.json` file loads that exact config regardless of its name. A directory enables config-less generation with settings supplied through CLI flags.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:<name>": "svg-sprites --mode <mode-key> <sprite-directory>"
|
"sprite:<name>": "svg-sprites <path-to-config>",
|
||||||
|
"sprite:<name>:cli": "svg-sprites --mode <mode-key> <sprite-directory>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not pass multiple paths, a glob, or the path to the config file itself. For multiple modern sprites, create a separate command for each directory.
|
Do not use incomplete `react`, `next@app`, or `next@pages` keys, the removed `legacy` mode, or the not-yet-implemented `standalone` mode. Create one command per config file or directory when the project has multiple sprites.
|
||||||
|
|
||||||
Identify legacy mode by its contract, not by the number of sprites:
|
|
||||||
|
|
||||||
- `svg-sprites.config.ts` in the supplied root, with top-level `output` and a non-empty `sprites` array, is a legacy config even if it contains only one entry;
|
|
||||||
- each legacy entry uses `name`, `input`, and optional `format: 'stack' | 'symbol'`; the `mode` field is deprecated;
|
|
||||||
- a local `svg-sprite.config.ts` in a single sprite directory, with `name`, `description`, `inputFolder`, `inputFiles`, `transform`, and `generatedNotice`, belongs to the React/Next API even when the application has many such sprites.
|
|
||||||
|
|
||||||
Do not migrate a legacy config without an explicit request. Do not combine `defineLegacyConfig` or the `output`/`sprites` fields with `defineReactSpriteConfig` or `defineNextSpriteConfig`.
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
Establish the project's actual contract before making changes:
|
Establish the project's actual contract before making changes:
|
||||||
|
|
||||||
1. Read the root `package.json`, lockfile, and workspace configuration; identify the framework, bundler, and existing commands.
|
1. Read the root `package.json`, lockfile, and workspace configuration; identify the framework, bundler, and existing commands.
|
||||||
2. Find `svg-sprite.config.ts`, `svg-sprites.config.ts`, commands containing `svg-sprites`, and imports of generated components.
|
2. Find config files, commands containing `svg-sprites`, and imports of generated components. Config names are arbitrary; use the explicit CLI path and object fields.
|
||||||
3. For React, determine whether the project uses Vite or Webpack 5 from its scripts and configuration. For Next.js, separately determine the App/Pages Router and the bundler used by the actual `dev`/`build` commands.
|
3. For React, determine whether the project uses Vite or Webpack 5 from its scripts and configuration. For Next.js, separately determine the App/Pages Router and the bundler used by the actual `dev`/`build` commands.
|
||||||
4. Check existing `predev`, `prebuild`, `pretypecheck`, and orchestration scripts. Do not overwrite them.
|
4. Check existing `predev`, `prebuild`, `pretypecheck`, and orchestration scripts. Do not overwrite them.
|
||||||
5. For a new sprite, choose a target directory without imposing a particular application layer or architecture.
|
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'`.
|
6. Check TypeScript and alias settings. Package subpath exports require TypeScript 5+ with `moduleResolution: 'bundler'`, `'node16'`, or `'nodenext'`.
|
||||||
|
|
||||||
All paths in a modern config are relative to the directory containing `svg-sprite.config.ts`:
|
All config paths are relative to the directory containing the explicitly selected config file; in config-less mode they are relative to the supplied directory:
|
||||||
|
|
||||||
- `inputFolder` defaults to `./icons`;
|
- `inputFolder` defaults to `./icons`;
|
||||||
- `inputFiles` contains additional relative paths to individual SVGs and is merged with `inputFolder`;
|
- `inputFiles` contains additional relative paths to individual SVGs and is merged with `inputFolder`;
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
Use the configuration helper for autocomplete and type checking:
|
Use the configuration helper for autocomplete and type checking:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -31,7 +32,7 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
The object contract is the same for React and Next.js. Use `defineNextSpriteConfig(...)` instead for a Next.js sprite.
|
The object contract is the same for React and Next.js; only the full `mode` differs.
|
||||||
|
|
||||||
`name` must begin with an ASCII letter and use kebab-case. The example `file-manager` produces `FileManagerIcon`, `FileManagerIconName`, and `fileManagerIconNames`. Another sprite gets its own names. If `name` is omitted, the generator derives it from the directory.
|
`name` must begin with an ASCII letter and use kebab-case. The example `file-manager` produces `FileManagerIcon`, `FileManagerIconName`, and `fileManagerIconNames`. Another sprite gets its own names. If `name` is omitted, the generator derives it from the directory.
|
||||||
|
|
||||||
@@ -40,15 +41,15 @@ Add a separate command with the selected mode key and one path:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"sprites": "npm run sprite:file-manager"
|
"sprites": "npm run sprite:file-manager"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For Next.js, substitute the full key, for example `next@app/turbopack`. For multiple sprites, add one `sprite:<name>` command per directory and invoke them sequentially from `sprites`.
|
For Next.js, set the full key in the config, for example `next@app/turbopack`. For multiple sprites, add one `sprite:<name>` command per config file and invoke them sequentially from `sprites`.
|
||||||
|
|
||||||
Generated files are excluded from Git by default, so run `sprites` before any process that needs `index.ts`, the types, or the asset. Add it to `predev`, `prebuild`, and, when a `typecheck` script exists, `pretypecheck`.
|
Generated files in `.svg-sprite` are excluded from Git by default, so run `sprites` before any process that needs the component, types, or asset. If the project imports the sprite-module root, create a user-owned `index.ts` with `export * from './.svg-sprite'`. Add generation to `predev`, `prebuild`, and, when a `typecheck` script exists, `pretypecheck`.
|
||||||
|
|
||||||
If a lifecycle script is missing, create it. If it already exists, preserve its command and append generation with `&&`; for example, change `"prebuild": "npm run lint"` to `"prebuild": "npm run lint && npm run sprites"`. Never replace an existing `pre*` script with generation alone, and never create a duplicate JSON key.
|
If a lifecycle script is missing, create it. If it already exists, preserve its command and append generation with `&&`; for example, change `"prebuild": "npm run lint"` to `"prebuild": "npm run lint && npm run sprites"`. Never replace an existing `pre*` script with generation alone, and never create a duplicate JSON key.
|
||||||
|
|
||||||
|
|||||||
@@ -5,23 +5,33 @@ After generation, the selected directory has this structure:
|
|||||||
```text
|
```text
|
||||||
svg-sprite/
|
svg-sprite/
|
||||||
├── icons/ # user-owned sources
|
├── icons/ # user-owned sources
|
||||||
├── svg-sprite.config.ts # user-owned config
|
├── svg-sprite.config.ts # recommended config name
|
||||||
|
├── index.ts # optional user-owned barrel
|
||||||
├── .gitignore # managed by the generator
|
├── .gitignore # managed by the generator
|
||||||
├── index.ts # public production entry point
|
└── .svg-sprite/
|
||||||
├── manifest.ts # separate debug entry point
|
├── state.json # ownership registry and contract version
|
||||||
└── generated/
|
├── index.js
|
||||||
├── .svg-sprites.manifest.json # ownership registry
|
├── index.d.ts
|
||||||
├── react-component.tsx
|
├── icon-data.js
|
||||||
|
├── icon-data.d.ts
|
||||||
├── sprite.svg
|
├── sprite.svg
|
||||||
├── styles.module.css
|
├── svg-sprite.manifest.js
|
||||||
└── types.ts
|
├── svg-sprite.manifest.d.ts
|
||||||
|
└── react/
|
||||||
|
├── react-component.js
|
||||||
|
├── react-component.d.ts
|
||||||
|
└── react-component.module.css
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit only the source SVGs and `svg-sprite.config.ts`. Do not manually change `.gitignore`, `index.ts`, `manifest.ts`, or anything in `generated/`: the next generation will overwrite them. Import the production API from the root `index.ts`, not through a deep import from `generated/`.
|
Edit the source SVGs, selected config, and user-owned `index.ts`. Do not manually change `.gitignore` or anything in `.svg-sprite`: the next generation will overwrite them. To import from the sprite-module root, create a barrel:
|
||||||
|
|
||||||
The generator owns only the listed root files and immediate files in `generated/`. The `.svg-sprites.manifest.json` registry allows stale generated files to be removed, but the writer refuses to overwrite or delete any file without a generated marker. Do not remove the marker, bypass the refusal, or replace generated paths with symlinks: move the user-owned file or choose a different directory.
|
```ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
The public entry point exports the component, props/style types, a readonly array of names, and the icon-name union type. `manifest.ts` contains the URL, target, icon list, and icon metadata for debug tools and is not imported by the production component.
|
The generator owns `.gitignore` and files inside `.svg-sprite`. The `state.json` registry allows stale generated files to be removed, but the writer refuses to overwrite or delete any file without a generated marker. Do not remove the marker, bypass the refusal, or replace generated paths with symlinks: move the user-owned file or choose a different directory.
|
||||||
|
|
||||||
|
The internal `index.js` exports the component from `react/react-component.js` and the readonly name array; the adjacent `index.d.ts` adds props/style types and the icon-name union. The manifest contains the mode, URL, target, icon list, and icon metadata for debug tools and is not imported by the production component.
|
||||||
|
|
||||||
The sprite remains a separate content-hashed asset; SVG path data is not embedded in JavaScript:
|
The sprite remains a separate content-hashed asset; SVG path data is not embedded in JavaScript:
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ Automatic replacement targets `fill`/`stroke` attributes and inline `style`. The
|
|||||||
|
|
||||||
`SpriteViewer` is optional. Import it from `@gromlab/svg-sprites/react` only on a debug route:
|
`SpriteViewer` is optional. Import it from `@gromlab/svg-sprites/react` only on a debug route:
|
||||||
|
|
||||||
- in Vite, pass the result of a string-literal `import.meta.glob('/src/**/svg-sprite/manifest.ts')`;
|
- in Vite, pass the result of a string-literal `import.meta.glob('/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js')`;
|
||||||
- in Webpack, pass an array of static `() => import('.../manifest')` loaders;
|
- in Webpack, pass an array of static `() => import('.../manifest')` loaders;
|
||||||
- in Next.js, use the same static loaders, and for the App Router put the Viewer in a separate file with `'use client'`.
|
- in Next.js, use the same static loaders, and for the App Router put the Viewer in a separate file with `'use client'`.
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
After changing a config or SVG, perform these required quick checks:
|
After changing a config or SVG, perform these required quick checks:
|
||||||
|
|
||||||
1. Run the exact sprite command, for example `npm run sprite:file-manager`; it must exit with code `0` and report the name, icon count, mode, and `generated` directory.
|
1. Run the exact sprite command, for example `npm run sprite:file-manager`; it must exit with code `0` and report the name, icon count, mode, and `.svg-sprite` directory.
|
||||||
2. Confirm that `index.ts`, `manifest.ts`, `generated/sprite.svg`, `generated/react-component.tsx`, `generated/types.ts`, `generated/styles.module.css`, and `generated/.svg-sprites.manifest.json` exist.
|
2. Confirm that `.svg-sprite/index.js`, `.svg-sprite/index.d.ts`, `sprite.svg`, the `icon-data.js`/`.d.ts` and manifest `.js`/`.d.ts` pairs, `react/react-component.js`, its `.d.ts` and CSS Module, and `state.json` exist.
|
||||||
3. Confirm that the new icon appears in the readonly name array and is accepted by the `icon` prop.
|
3. Confirm that the new icon appears in the readonly name array and is accepted by the `icon` prop.
|
||||||
4. Run the project's existing type check, for example `npm run typecheck`.
|
4. Run the project's existing type check, for example `npm run typecheck`.
|
||||||
5. Check that `target` in `manifest.ts` matches the selected mode key; the generated asset expression must use `?no-inline` for Vite and `new URL(...)` for Webpack/Next.
|
5. Check that `target` in `.svg-sprite/svg-sprite.manifest.js` matches the selected mode key; the generated asset expression must use `?no-inline` for Vite and `new URL(...)` for Webpack/Next.
|
||||||
|
|
||||||
Do not run a full production build solely to verify a changed icon list. It is required when the bundler target, asset pipeline configuration, Next router/bundler, or Webpack loader changed, or when diagnosing a runtime URL failure.
|
Do not run a full production build solely to verify a changed icon list. It is required when the bundler target, asset pipeline configuration, Next router/bundler, or Webpack loader changed, or when diagnosing a runtime URL failure.
|
||||||
|
|
||||||
|
|||||||
@@ -4,21 +4,20 @@ Match the symptom to the relevant check and fix the root cause:
|
|||||||
|
|
||||||
| Symptom | Likely cause | Action |
|
| Symptom | Likely cause | Action |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `Missing required argument: --mode` or `Missing sprite path` | Incomplete CLI command | Pass `--mode <full-key>` and one sprite directory. |
|
| `Missing sprite config file or module directory` | The positional path is missing | Pass one config file or a directory for config-less generation. |
|
||||||
| `Expected one sprite path` | Multiple paths were passed | Create one command per modern sprite and combine the scripts. |
|
| `Expected one config file or module directory` | Multiple paths were passed | Create one command per sprite and combine the scripts. |
|
||||||
| `React mode requires a target` or `Unsupported Next.js target` | A shortened or unsupported key was used | Select one of the seven mode keys from the table; do not use `standalone`. |
|
| `Sprite mode is required` | Mode is absent from both config and CLI | Add `mode` to the object or pass the full `--mode`. |
|
||||||
| `React config file not found` | The CLI path does not point to a directory containing `svg-sprite.config.ts` | Fix the positional path; do not pass the config file itself. |
|
| `Unsupported sprite config extension` | The supplied file is not `.ts`, `.js`, or `.json` | Use a supported config format. |
|
||||||
| Legacy config is missing or read by the wrong pipeline | `svg-sprites.config.ts` and `svg-sprite.config.ts` were confused | Identify the API by the config filename and fields, regardless of the number of `sprites` entries. |
|
|
||||||
| `Input directory does not exist` | The relative path is wrong or an explicitly configured folder is missing | Resolve it from the config directory; create the folder or correct `inputFolder`. |
|
| `Input directory does not exist` | The relative path is wrong or an explicitly configured folder is missing | Resolve it from the config directory; create the folder or correct `inputFolder`. |
|
||||||
| Icons from a subdirectory are missing | Recursive scanning was assumed | Move the SVG to the top level of `inputFolder` or list it in `inputFiles`. |
|
| Icons from a subdirectory are missing | Recursive scanning was assumed | Move the SVG to the top level of `inputFolder` or list it in `inputFiles`. |
|
||||||
| `SVG file does not exist`, `File is not an SVG`, or an empty input set | Invalid `inputFiles`, extension, or sources | Correct the path/extension and provide at least one input SVG. |
|
| `SVG file does not exist`, `File is not an SVG`, or an empty input set | Invalid `inputFiles`, extension, or sources | Correct the path/extension and provide at least one input SVG. |
|
||||||
| Icon name or SVG ID collision | Two different files have the same basename, or a hash ID collides with a name | Rename one source SVG; do not select a file implicitly. |
|
| Icon name or SVG ID collision | Two different files have the same basename, or a hash ID collides with a name | Rename one source SVG; do not select a file implicitly. |
|
||||||
| `Refusing to overwrite/delete a user file` | A user file occupies a managed path or lost its marker | Do not bypass the protection: move the file or choose another sprite directory and regenerate. |
|
| `Refusing to overwrite/delete a user file` | A user file occupies a managed path or lost its marker | Do not bypass the protection: move the file or choose another sprite directory and regenerate. |
|
||||||
| Missing `index.ts` or name absent from autocomplete | Generation did not run after the change, or the type server cached an old module | Run the sprite command, then typecheck; restart the TypeScript server if necessary. |
|
| Missing `.svg-sprite/index.js` or name absent from autocomplete | Generation did not run, the user barrel does not export `.svg-sprite`, or the type server cached an old module | Run the sprite command, check `export * from './.svg-sprite'`, then typecheck; restart the TypeScript server if necessary. |
|
||||||
| SVG does not load or the URL is wrong | Mode and bundler differ, Webpack `publicPath` is wrong, or a custom loader intercepted the asset | Align mode with the build command, check Asset Modules/`publicPath`, and exclude the generated SVG from the incompatible loader. |
|
| SVG does not load or the URL is wrong | Mode and bundler differ, Webpack `publicPath` is wrong, or a custom loader intercepted the asset | Align mode with the build command, check Asset Modules/`publicPath`, and exclude the generated SVG from the incompatible loader. |
|
||||||
| Next build differs between SSR and browser | The module targets another bundler/router, or the URL was rewritten manually | Restore the generated `new URL(...)`, select the exact Next mode, and regenerate. |
|
| Next build differs between SSR and browser | The module targets another bundler/router, or the URL was rewritten manually | Restore the generated `new URL(...)`, select the exact Next mode, and regenerate. |
|
||||||
| `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. |
|
| `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. |
|
| 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 | Manifests were not generated, the glob/import is not static, or the Client Component boundary is wrong | Generate sprites first; use a literal glob for Vite, static loaders for Webpack/Next, and add `'use client'` only to the App Router Viewer page. |
|
| Viewer is empty | Manifests were not generated, the glob/import is not static, or the Client Component boundary is wrong | Generate sprites first; use a literal glob for Vite, static loaders for Webpack/Next, and add `'use client'` only to the App Router Viewer page. |
|
||||||
|
|
||||||
For an unknown error, record the complete CLI command, mode, config path, and first stack/error message. Then reduce it to one sprite without deleting user files or protective markers.
|
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 protective markers.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Inspect the source SVG before editing it:
|
|||||||
npm run sprite:file-manager
|
npm run sprite:file-manager
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the actual package script for the sprite. Then compare the source with `generated/sprite.svg` and the manifest; do not draw conclusions from a successful exit code alone.
|
Use the actual package script for the sprite. Then compare the source with `.svg-sprite/sprite.svg` and the manifest; do not draw conclusions from a successful exit code alone.
|
||||||
|
|
||||||
Pay particular attention to:
|
Pay particular attention to:
|
||||||
|
|
||||||
@@ -36,9 +36,10 @@ The compiler first applies SVGO `preset-default` while preserving `viewBox`, the
|
|||||||
All three options default to `true` and apply to the entire sprite, not to individual icons.
|
All three options default to `true` and apply to the entire sprite, not to individual icons.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'illustrations',
|
name: 'illustrations',
|
||||||
transform: {
|
transform: {
|
||||||
removeSize: false,
|
removeSize: false,
|
||||||
@@ -48,7 +49,7 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
This is a config for one of potentially many sprite directories in a project; its directory does not have to match a module/feature directory. Use `defineNextSpriteConfig(...)` with the same `transform` for Next; in legacy mode it belongs at the top level of `defineLegacyConfig(...)`.
|
This is a config for one of potentially many sprite modules in a project; its directory does not have to match a module/feature directory. For Next, use the corresponding full `mode` with the same `transform`.
|
||||||
|
|
||||||
## Dimensions and viewBox
|
## Dimensions and viewBox
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ Correct source preparation:
|
|||||||
|
|
||||||
If physical dimensions are part of an illustration's contract, set `removeSize: false` and verify component-prop behavior. Do not preserve width/height as a substitute for a missing viewBox.
|
If physical dimensions are part of an illustration's contract, set `removeSize: false` and verify component-prop behavior. Do not preserve width/height as a substitute for a missing viewBox.
|
||||||
|
|
||||||
React and legacy compilation leave the root sprite `rootViewBox` disabled; Next enables it. Every shape must still have its own valid viewBox, which is included in the manifest and used by the Viewer.
|
React compilation leaves the root sprite `rootViewBox` disabled; Next enables it. Every shape must still have its own valid viewBox, which is included in the manifest and used by the Viewer.
|
||||||
|
|
||||||
## Colors
|
## Colors
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ It is preserved as the fragment ID. Other names, such as `folder open.svg` or `2
|
|||||||
<FileManagerIcon icon="folder open" />
|
<FileManagerIcon icon="folder open" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not manually construct `#folder open`. Use the generated component or `manifest.ts`, which records both `name` and the actual `id`.
|
Do not manually construct `#folder open`. Use the generated component or `.svg-sprite/svg-sprite.manifest.js`, which records both `name` and the actual `id`.
|
||||||
|
|
||||||
Different files with the same basename are forbidden, even from different directories. Rename one source meaningfully; `inputFiles` order does not select a winner.
|
Different files with the same basename are forbidden, even from different directories. Rename one source meaningfully; `inputFiles` order does not select a winner.
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ External stack-fragment support and paint-server behavior can vary across browse
|
|||||||
3. Open the generated sprite and find the shape using the ID from the manifest.
|
3. Open the generated sprite and find the shape using the ID from the manifest.
|
||||||
4. Statically compare `viewBox`, IDs, `url(#...)`, colors, and inline styles.
|
4. Statically compare `viewBox`, IDs, `url(#...)`, colors, and inline styles.
|
||||||
5. If the target/pipeline changed or a runtime issue is being diagnosed, build the production bundle and inspect the external hashed SVG.
|
5. If the target/pipeline changed or a runtime issue is being diagnosed, build the production bundle and inspect the external hashed SVG.
|
||||||
6. When SpriteViewer, legacy `preview.html`, and visual tools are available, test default colors and each `--icon-color-N` separately.
|
6. When SpriteViewer and visual tools are available, test default colors and each `--icon-color-N` separately.
|
||||||
7. When browser tools are available and the runtime risk warrants it, test SSR/hydration for Next.js and target browsers for external fragments.
|
7. When browser tools are available and the runtime risk warrants it, test SSR/hydration for Next.js and target browsers for external fragments.
|
||||||
8. Do not claim visual or accessibility equivalence between source and output without the necessary tools and an actual comparison.
|
8. Do not claim visual or accessibility equivalence between source and output without the necessary tools and an actual comparison.
|
||||||
|
|
||||||
@@ -172,4 +173,4 @@ External stack-fragment support and paint-server behavior can vary across browse
|
|||||||
- A manual fragment fails for a name containing spaces: use the ID from the manifest.
|
- A manual fragment fails for a name containing spaces: use the ID from the manifest.
|
||||||
- One complex icon requires different transforms: move it to a separate sprite; per-icon transform config is not supported.
|
- One complex icon requires different transforms: move it to a separate sprite; per-icon transform config is not supported.
|
||||||
|
|
||||||
Target-specific execution and verification are documented in [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md), [next-pages.md](next-pages.md), and [legacy.md](legacy.md).
|
Target-specific execution and verification are documented in [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md), and [next-pages.md](next-pages.md).
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
# Legacy mode: operational reference
|
|
||||||
|
|
||||||
## When to use this reference
|
|
||||||
|
|
||||||
Use this document when the project already has a root `svg-sprites.config.ts`, centralized output, multiple `sprites` entries, the `symbol` format, or a standalone `preview.html`. Do not migrate such a project to local React/Next modules without an explicit request; for a planned migration, open [migration-1.md](migration-1.md).
|
|
||||||
|
|
||||||
## What distinguishes legacy mode
|
|
||||||
|
|
||||||
- One config manages one or more sprites.
|
|
||||||
- Results are written as `<name>.sprite.svg` into a shared `output`.
|
|
||||||
- Both `stack` and `symbol` are supported; the default format is `stack`.
|
|
||||||
- `preview` is enabled by default and creates a shared `preview.html`.
|
|
||||||
- There is no generated React component, manifest module, local `.gitignore`, or managed-writer protection.
|
|
||||||
- Legacy paths in a loaded config are resolved relative to the directory passed to the CLI.
|
|
||||||
|
|
||||||
## Config and execution
|
|
||||||
|
|
||||||
Install the package as a development dependency:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
`svg-sprites.config.ts`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineLegacyConfig({
|
|
||||||
output: 'public/sprites',
|
|
||||||
preview: true,
|
|
||||||
transform: {
|
|
||||||
removeSize: true,
|
|
||||||
replaceColors: true,
|
|
||||||
addTransition: true,
|
|
||||||
},
|
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'logos',
|
|
||||||
input: [
|
|
||||||
'src/assets/logos/product.svg',
|
|
||||||
'src/assets/shared/brand.svg',
|
|
||||||
],
|
|
||||||
format: 'stack',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Unlike local React/Next configs, each of which describes one of potentially many sprites, a single legacy config retains the specific ability to manage one or more sprite entries.
|
|
||||||
|
|
||||||
Script:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy .",
|
|
||||||
"prebuild": "npm run sprites"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Run `npm run sprites` from the project root.
|
|
||||||
|
|
||||||
The CLI path points to the directory containing `svg-sprites.config.ts`. Do not pass the file itself. For a config in another directory, pass that directory explicitly.
|
|
||||||
|
|
||||||
## Input semantics
|
|
||||||
|
|
||||||
- A string `input` denotes a directory; only top-level SVG files are read, sorted by name.
|
|
||||||
- An array `input` denotes an exact file list; an empty array is an error.
|
|
||||||
- The extension check is case-sensitive and requires the `.svg` suffix.
|
|
||||||
- Every file in an array is checked for existence.
|
|
||||||
- Unlike a local React config, a legacy entry cannot merge a folder and a list. For a mixed set, list every file or split the inputs into separate entries.
|
|
||||||
- `name` is used directly in the output filename; choose unique safe names and do not create two entries with the same output name.
|
|
||||||
|
|
||||||
## Format selection and runtime
|
|
||||||
|
|
||||||
Use `symbol` for existing `<svg><use>` integration:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg width="24" height="24" aria-label="Done">
|
|
||||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
|
||||||
</svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
`stack` works with `<svg><use>`, `<img src="...svg#check">`, and CSS URLs. For new React/Next code, do not automatically build a local component over legacy output; select the appropriate modern mode first.
|
|
||||||
|
|
||||||
Page CSS custom properties control content through `<svg><use>`, but do not cross into a document loaded as `<img>` or `background-image`. `symbol` is not intended for `<img>`.
|
|
||||||
|
|
||||||
Names containing spaces or unsafe characters receive a hash ID in the form `icon-<16 hex>`. Do not assume the basename always equals the fragment; inspect the generated SVG or preview.
|
|
||||||
|
|
||||||
## Preview
|
|
||||||
|
|
||||||
With `preview: true`, `output/preview.html` is created after all SVGs. It contains data and inline copies of generated sprites. When diagnosing runtime behavior and browser tools are available, open it to inspect the icon count, `viewBox`, and `--icon-color-N` values.
|
|
||||||
|
|
||||||
With `preview: false`, no new preview is created. The generator is not a cleaner for arbitrary output files: if an old `preview.html` is no longer needed, delete it only after confirming that it is a previous generated artifact.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run sprites
|
|
||||||
npm run typecheck
|
|
||||||
```
|
|
||||||
|
|
||||||
Generation and the project's typecheck are the required quick checks. For each entry, verify that:
|
|
||||||
|
|
||||||
- `public/sprites/<name>.sprite.svg` exists;
|
|
||||||
- the logged format and icon count are correct;
|
|
||||||
- the expected `<symbol id="...">` or nested `<svg id="...">` elements are present;
|
|
||||||
- `preview.html` is created only when preview is enabled;
|
|
||||||
- SVGs with complex `defs` were checked according to [complex-svg.md](complex-svg.md).
|
|
||||||
|
|
||||||
Run a production build and browser/Network checks additionally only when the output/public pipeline changed or a runtime issue is being diagnosed. In that case, inspect the real application URL with its public base path and, if visual tools are available, the contents of `preview.html`; do not claim visual or accessibility results without that verification.
|
|
||||||
|
|
||||||
## Common failures
|
|
||||||
|
|
||||||
- `Config file not found`: the CLI path is not a directory containing `svg-sprites.config.ts`.
|
|
||||||
- `Config file must have a default export`: export the config through `defineLegacyConfig(...)`.
|
|
||||||
- Deprecated `mode`: the `sprites[].mode` field was renamed to `format`.
|
|
||||||
- `sprites must be a non-empty array`: a legacy config cannot be empty.
|
|
||||||
- `Input directory does not exist` or `SVG file does not exist`: remember that paths are resolved from the config directory when loaded by the CLI.
|
|
||||||
- Nested SVGs are missing: directory scanning is not recursive.
|
|
||||||
- `Preview template not found` when running from package sources: build the package preview template; it is included in the published distribution.
|
|
||||||
- Color does not change in `<img>`: it is an isolated SVG document; use `<svg><use>` or colors defined in advance.
|
|
||||||
- Old output files remain after an entry is removed: the legacy generator writes current results but does not own cleanup of the entire output directory.
|
|
||||||
|
|
||||||
Programmatic execution variants and path-resolution differences are documented in [programmatic-api.md](programmatic-api.md).
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
# Migrating from the legacy 0.1.x API to latest: operational reference
|
|
||||||
|
|
||||||
## When to use this reference
|
|
||||||
|
|
||||||
Use this document only when version `0.1.x` is installed or was previously used, or when the project has old `svg-sprites` invocations without `--mode`, `defineConfig`, `generate`, `loadConfig`, a `sprites[].mode` field, `publicPath`, or a shared `<SvgSprite>` component. Do not perform this migration as an incidental refactor.
|
|
||||||
|
|
||||||
## Inventory before changes
|
|
||||||
|
|
||||||
First record the project's current contract:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm ls @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Install the current package as a development dependency before updating the config and scripts:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Find and read:
|
|
||||||
|
|
||||||
- `svg-sprites.config.ts` and `svg-sprite.config.ts`;
|
|
||||||
- scripts that invoke `svg-sprites`;
|
|
||||||
- imports of `defineConfig`, `generate`, `loadConfig`, and `SvgSprite`;
|
|
||||||
- references to `publicPath`, `.sprite.svg`, the old generated component, and preview;
|
|
||||||
- `.gitignore` rules, SVG loaders, and CI generation steps.
|
|
||||||
|
|
||||||
Before changing anything, choose one of the two paths below. Do not combine them in one CLI invocation.
|
|
||||||
|
|
||||||
## Path A: retain the centralized legacy pipeline
|
|
||||||
|
|
||||||
Choose this path when the application depends on shared `public/sprites`, `symbol`, static URLs, or `preview.html`.
|
|
||||||
|
|
||||||
API mapping:
|
|
||||||
|
|
||||||
| Legacy 0.1.x API | Latest API |
|
|
||||||
|---|---|
|
|
||||||
| `defineConfig` | `defineLegacyConfig` |
|
|
||||||
| `sprites[].mode` | `sprites[].format` |
|
|
||||||
| `generate` | `generateLegacy` |
|
|
||||||
| `loadConfig` | `loadLegacyConfig` |
|
|
||||||
| CLI without mode | `svg-sprites --mode legacy <config-dir>` in a package script |
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineLegacyConfig({
|
|
||||||
output: 'public/sprites',
|
|
||||||
preview: true,
|
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy ."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Run it with `npm run sprites`.
|
|
||||||
|
|
||||||
`publicPath` and generation of the old shared React component were removed. If the application used that component, legacy mode preserves the SVG asset, but the React wrapper must be replaced separately. The complete legacy workflow is in [legacy.md](legacy.md).
|
|
||||||
|
|
||||||
## Path B: move to local React/Next modules
|
|
||||||
|
|
||||||
Choose this path when typed components, bundler-hashed assets, Server Components, or splitting a large set are required.
|
|
||||||
|
|
||||||
For each required sprite, create a project directory with local `svg-sprite.config.ts` and, when using a folder, `icons/`. The directory does not have to be a module/feature directory; each config describes one of potentially many sprites:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
|
||||||
name: 'global',
|
|
||||||
inputFolder: './icons',
|
|
||||||
inputFiles: ['../../../shared/icons/check.svg'],
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
For Next.js, use `defineNextSpriteConfig(...)` instead. Then select exactly one mode:
|
|
||||||
|
|
||||||
| Environment | Mode |
|
|
||||||
|---|---|
|
|
||||||
| React + Vite | `react@vite` |
|
|
||||||
| React + Webpack 5 | `react@webpack` |
|
|
||||||
| Next App + Turbopack | `next@app/turbopack` |
|
|
||||||
| Next App + Webpack 5 | `next@app/webpack` |
|
|
||||||
| Next Pages + Turbopack | `next@pages/turbopack` |
|
|
||||||
| Next Pages + Webpack 5 | `next@pages/webpack` |
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprite:global": "svg-sprites --mode react@vite src/ui/global/svg-sprite",
|
|
||||||
"sprites": "npm run sprite:global"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Run it with `npm run sprite:global`.
|
|
||||||
|
|
||||||
Replace the old generic component:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// Before
|
|
||||||
<SvgSprite icon="check" />
|
|
||||||
|
|
||||||
// After, with name: 'global'
|
|
||||||
<GlobalIcon icon="check" />
|
|
||||||
```
|
|
||||||
|
|
||||||
The new module creates its own local `.gitignore`, `index.ts`, `manifest.ts`, and `generated/`. The bundler publishes the SVG; do not preserve the old `publicPath` or copy the sprite into `public`.
|
|
||||||
|
|
||||||
Select the detailed procedure: [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md), or [next-pages.md](next-pages.md).
|
|
||||||
|
|
||||||
## Programmatic API changes
|
|
||||||
|
|
||||||
The package is now ESM-only:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { compileSpriteContent, generateLegacy } from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not use `require()`. `compileSpriteContent(...)` now returns `Promise<Uint8Array>` rather than a Node-specific `Buffer` declaration:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const bytes = await compileSpriteContent(folder)
|
|
||||||
await fs.promises.writeFile('sprite.svg', bytes)
|
|
||||||
```
|
|
||||||
|
|
||||||
If old code called `generate`, replace it with `generateLegacy`; for local modules, use `generateReactSprite` or `generateNextSprite`. See [programmatic-api.md](programmatic-api.md) for exact signatures.
|
|
||||||
|
|
||||||
## Safe migration order
|
|
||||||
|
|
||||||
1. Record the current icon names, formats, public URLs, and color expectations.
|
|
||||||
2. When migrating imports, update the dependency to latest and update the config API, but do not delete old artifacts until new generation succeeds.
|
|
||||||
3. Add an explicit mode and directory to every local/CI script.
|
|
||||||
4. Generate the new output.
|
|
||||||
5. Replace imports and JSX usages; check the TypeScript icon-name unions.
|
|
||||||
6. If the target/pipeline changed or a runtime issue is being diagnosed, inspect asset URLs and SSR/SSG; assess visual results only with tools capable of doing so.
|
|
||||||
7. Only then remove confirmed old generated files and obsolete ignore/loader rules.
|
|
||||||
|
|
||||||
Do not delete an entire directory that may contain source SVGs or user-owned files. The current writer refuses to overwrite files without a generated marker; do not bypass this protection.
|
|
||||||
|
|
||||||
## Post-migration verification
|
|
||||||
|
|
||||||
Minimum checks for an npm project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run sprites
|
|
||||||
npm run typecheck
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the project's actual script names. Generation and typechecking are the required quick checks. Add a production build, browser, and Network checks only when the migration changes the target/pipeline or a runtime issue is being diagnosed. Verify that:
|
|
||||||
|
|
||||||
- no script invokes the CLI without `--mode` and a path;
|
|
||||||
- the config helper and CLI mode belong to the same pipeline;
|
|
||||||
- a local manifest contains the expected target, while legacy output uses the expected format;
|
|
||||||
- obsolete `publicPath`, `sprites[].mode`, and removed API imports are gone;
|
|
||||||
- generated files are created before typechecking/building in a clean checkout;
|
|
||||||
- every old icon name remains available or was intentionally renamed;
|
|
||||||
- colors and complex SVGs were examined according to [complex-svg.md](complex-svg.md), without claims of visual or accessibility correctness when tools are unavailable;
|
|
||||||
- `SpriteViewer` replaced a separate preview only for React/Next; legacy mode may still use `preview.html`.
|
|
||||||
|
|
||||||
## Common failures
|
|
||||||
|
|
||||||
- `Missing required argument: --mode`: an old script was not updated.
|
|
||||||
- `React mode requires a target` or `Next.js mode requires a router and bundler`: a shortened mode was used instead of the full key.
|
|
||||||
- Deprecated `mode`: a legacy entry still has `sprites[].mode`.
|
|
||||||
- `icons was renamed to inputFolder`: the old field was moved into a local React/Next config without being renamed.
|
|
||||||
- `require() of ES Module`: the build script was not converted to ESM/import.
|
|
||||||
- Icons disappeared: local `inputFolder` scanning is shallow, or shared files were not added through `inputFiles`.
|
|
||||||
- Runtime still requests old `/sprites/...` URLs: JSX/CSS usage was not migrated to the generated component or new asset URL.
|
|
||||||
- One sprite is generated with multiple targets: CI and local scripts disagree; retain one target matching the actual bundler.
|
|
||||||
@@ -30,9 +30,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -41,7 +42,7 @@ export default defineNextSpriteConfig({
|
|||||||
```
|
```
|
||||||
|
|
||||||
- The project chooses the directory for each specific sprite; it does not have to be a module/feature directory. Each config describes one of potentially many application sprites.
|
- The project chooses the directory for each specific sprite; it does not have to be a module/feature directory. Each config describes one of potentially many application sprites.
|
||||||
- The config filename is singular: `svg-sprite.config.ts`.
|
- `svg-sprite.config.ts` is the recommended name; the CLI accepts an explicitly selected `.ts`, `.js`, or `.json` file with any name.
|
||||||
- Paths are relative to its directory; `inputFolder` scanning is shallow.
|
- Paths are relative to its directory; `inputFolder` scanning is shallow.
|
||||||
- The local folder and `inputFiles` are merged. Equal basenames from different files are forbidden.
|
- The local folder and `inputFiles` are merged. Equal basenames from different files are forbidden.
|
||||||
- If no name is configured, it is derived from the directory; for a directory named `svg-sprite`, the parent directory name is used. An explicit `name` is more stable when files move.
|
- If no name is configured, it is derived from the directory; for a directory named `svg-sprite`, the parent directory name is used. An explicit `name` is more stable when files move.
|
||||||
@@ -56,7 +57,7 @@ Example scripts for Turbopack:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -84,7 +85,7 @@ export default function Page() {
|
|||||||
|
|
||||||
`width` and `height` are optional in JSX; set the size with a CSS class or `wrapped`. Do not add a Client Component boundary solely for the icon. The generated module builds the asset URL with static `new URL('./sprite.svg', import.meta.url).href`; the same mechanism is used during SSR and in the browser.
|
`width` and `height` are optional in JSX; set the size with a CSS class or `wrapped`. Do not add a Client Component boundary solely for the icon. The generated module builds the asset URL with static `new URL('./sprite.svg', import.meta.url).href`; the same mechanism is used during SSR and in the browser.
|
||||||
|
|
||||||
Do not import from `generated/` or move the SVG into `public`. Managed files (`generated/`, `index.ts`, `manifest.ts`, `.gitignore`) are regenerated.
|
Do not move the SVG into `public`. The generator rewrites `.svg-sprite` and `.gitignore`; the root `index.ts` is application-owned and may contain `export * from './.svg-sprite'`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ npm run build
|
|||||||
|
|
||||||
After the required generation and typecheck, verify that:
|
After the required generation and typecheck, verify that:
|
||||||
|
|
||||||
- `manifest.ts` contains the exact target `next@app/turbopack` or `next@app/webpack`;
|
- `.svg-sprite/svg-sprite.manifest.js` contains the exact target `next@app/turbopack` or `next@app/webpack`;
|
||||||
- the server page compiles without adding `'use client'`.
|
- the server page compiles without adding `'use client'`.
|
||||||
|
|
||||||
During a conditional production/runtime check, also verify that:
|
During a conditional production/runtime check, also verify that:
|
||||||
@@ -140,7 +141,7 @@ During a conditional production/runtime check, also verify that:
|
|||||||
- Build passes with one bundler but the runtime asset breaks with another: regenerate for the target actually used by the build.
|
- Build passes with one bundler but the runtime asset breaks with another: regenerate for the target actually used by the build.
|
||||||
- Webpack was selected, but the build used Turbopack: use the project's Webpack build command and `next@app/webpack`.
|
- Webpack was selected, but the build used Turbopack: use the project's Webpack build command and `next@app/webpack`.
|
||||||
- Viewer causes a Server Component error: the Viewer file needs `'use client'`; the generated icon component does not.
|
- Viewer causes a Server Component error: the Viewer file needs `'use client'`; the generated icon component does not.
|
||||||
- `React config file not found`: the command received the path to `app/`, `icons/`, or the config file instead of the sprite directory.
|
- Config not found: pass the full path to an existing `.ts`, `.js`, or `.json` config file.
|
||||||
- Two CI jobs generate different targets in one checkout: separate their directories or ensure each job uses one consistent target.
|
- Two CI jobs generate different targets in one checkout: separate their directories or ensure each job uses one consistent target.
|
||||||
- Asset is missing under `basePath`/CDN: inspect Next asset handling and deployment configuration; do not replace the generated URL manually.
|
- Asset is missing under `basePath`/CDN: inspect Next asset handling and deployment configuration; do not replace the generated URL manually.
|
||||||
- Package subpath type error: use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
- Package subpath type error: use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@pages/webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -53,7 +54,7 @@ Example lifecycle scripts for Webpack:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -79,7 +80,7 @@ export function getServerSideProps() {
|
|||||||
|
|
||||||
`width` and `height` are optional in JSX; set the size with a CSS class or `wrapped`. The component works during SSR, SSG, and client navigation. It uses `new URL('./sprite.svg', import.meta.url).href` so Next emits an external hashed asset. Do not copy the generated SVG into `public` or construct the URL manually.
|
`width` and `height` are optional in JSX; set the size with a CSS class or `wrapped`. The component works during SSR, SSG, and client navigation. It uses `new URL('./sprite.svg', import.meta.url).href` so Next emits an external hashed asset. Do not copy the generated SVG into `public` or construct the URL manually.
|
||||||
|
|
||||||
Import the component and types only from the local `svg-sprite/index.ts`. Do not edit `generated/`, `index.ts`, `manifest.ts`, or the generated `.gitignore`.
|
Import the component and types from the local user-owned `svg-sprite/index.ts`, which re-exports `.svg-sprite`. Do not edit `.svg-sprite` or the generated `.gitignore`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ npm run build
|
|||||||
|
|
||||||
After the required generation and typecheck, verify that:
|
After the required generation and typecheck, verify that:
|
||||||
|
|
||||||
- `manifest.ts` contains `next@pages/turbopack` or `next@pages/webpack`;
|
- `.svg-sprite/svg-sprite.manifest.js` contains `next@pages/turbopack` or `next@pages/webpack`;
|
||||||
- `getServerSideProps`/`getStaticProps` does not import the package React Viewer entry.
|
- `getServerSideProps`/`getStaticProps` does not import the package React Viewer entry.
|
||||||
|
|
||||||
After the conditional production build, and only when browser tools are available, inspect the SSR route and navigation to it:
|
After the conditional production build, and only when browser tools are available, inspect the SSR route and navigation to it:
|
||||||
|
|||||||
@@ -1,244 +1,41 @@
|
|||||||
# Programmatic API: operational reference
|
# Programmatic API: operational reference
|
||||||
|
|
||||||
## Required installation
|
Use `generateSprite(source, overrides?)` as the primary Node.js API.
|
||||||
|
|
||||||
```bash
|
## From a config file
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Programmatic imports require the local development dependency shown above. This reference describes the installed package API.
|
|
||||||
|
|
||||||
## When to use this reference
|
|
||||||
|
|
||||||
Use this document when generation runs from an ESM build script, monorepo orchestration, custom CLI, or test rather than directly from a package script. For ordinary integration, prefer the CLI references: [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md), [next-pages.md](next-pages.md), or [legacy.md](legacy.md).
|
|
||||||
|
|
||||||
## Runtime and TypeScript
|
|
||||||
|
|
||||||
The main entry point is ESM-only and does not import React:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
import { generateSprite } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
|
await generateSprite('src/ui/icons/svg-sprite.config.ts')
|
||||||
```
|
```
|
||||||
|
|
||||||
Node.js 18+ is required. Do not use `require()`. The `@gromlab/svg-sprites/react` package subpath requires TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
`source` must point to a specific `.ts`, `.js`, or `.json` file. The file name is arbitrary and no discovery is performed. Its directory becomes the sprite module root and the base for relative paths.
|
||||||
|
|
||||||
## React module
|
## Without a config file
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
await generateSprite('src/ui/icons', {
|
||||||
|
mode: 'react@vite',
|
||||||
const result = await generateReactSprite(
|
name: 'app',
|
||||||
'src/ui/file-manager/svg-sprite',
|
inputFolder: './icons',
|
||||||
'vite',
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Target signature:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
type ReactAssetTarget = 'vite' | 'webpack'
|
|
||||||
```
|
|
||||||
|
|
||||||
`root` is resolved relative to the current `process.cwd()`. It is the selected directory for the specific sprite, not a required module/feature directory. Within it, the function loads only `svg-sprite.config.ts`, merges `inputFolder` and `inputFiles`, compiles `stack`, and safely updates managed files. Each such config describes one of potentially many sprites.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
type ReactSpriteGenerationResult = {
|
|
||||||
name: string
|
|
||||||
rootDir: string
|
|
||||||
generatedDir: string
|
|
||||||
spritePath: string
|
|
||||||
manifestPath: string
|
|
||||||
iconCount: number
|
|
||||||
target: 'vite' | 'webpack'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Pass the target explicitly. A value outside the union synchronously throws `Unsupported React asset target`.
|
|
||||||
|
|
||||||
## Next.js module
|
|
||||||
|
|
||||||
```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'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The result contains the React result fields, a `next@<router>/<bundler>` target, and `router` and `bundler`. Next generation always uses `stack` and includes a root `viewBox`. The selected options must match the actual Next build command.
|
|
||||||
|
|
||||||
## Config helpers and loaders
|
|
||||||
|
|
||||||
Helpers only return the object and provide autocomplete; they do not load files or run validation:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import {
|
|
||||||
defineLegacyConfig,
|
|
||||||
defineNextSpriteConfig,
|
|
||||||
defineReactSpriteConfig,
|
|
||||||
loadLegacyConfig,
|
|
||||||
loadReactSpriteConfig,
|
|
||||||
} from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const reactConfig = await loadReactSpriteConfig(
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
)
|
|
||||||
|
|
||||||
const legacyConfig = await loadLegacyConfig('.')
|
|
||||||
```
|
|
||||||
|
|
||||||
`loadReactSpriteConfig(root)` resolves `inputFolder`/`inputFiles` from `root` and returns a normalized config. Despite its name, Next mode uses the same loader.
|
|
||||||
|
|
||||||
`loadLegacyConfig(cwd)` looks for `cwd/svg-sprites.config.ts`, validates it, and converts `output` and `sprites[].input` into absolute paths relative to `cwd`.
|
|
||||||
|
|
||||||
## Legacy generation
|
|
||||||
|
|
||||||
Direct invocation:
|
|
||||||
|
|
||||||
```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
|
A directory enables config-less mode. `mode` must exist after settings are merged.
|
||||||
type SpriteResult = {
|
|
||||||
name: string
|
|
||||||
format: 'symbol' | 'stack'
|
|
||||||
spritePath: string
|
|
||||||
iconCount: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Important path nuance: `generateLegacy(config)` does not know the config file's location. Relative `output` and `input` paths are resolved from the current `process.cwd()`. If semantics must match the CLI for a config in another directory, call the loader first:
|
## Overrides
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const config = await loadLegacyConfig('config/sprites')
|
await generateSprite('src/ui/icons/custom.json', {
|
||||||
const results = await generateLegacy(config)
|
mode: 'react@webpack',
|
||||||
```
|
inputFiles: ['../../shared/search.svg'],
|
||||||
|
transform: { addTransition: false },
|
||||||
## Low-level compilation
|
|
||||||
|
|
||||||
Main exports:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import {
|
|
||||||
compileSprite,
|
|
||||||
compileSpriteContent,
|
|
||||||
createShapeTransform,
|
|
||||||
generatePreview,
|
|
||||||
resolveSpriteEntry,
|
|
||||||
resolveSprites,
|
|
||||||
} from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
Minimal in-memory example:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { compileSpriteContent, resolveSpriteEntry } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const folder = resolveSpriteEntry({
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'stack',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const bytes = await compileSpriteContent(
|
|
||||||
folder,
|
|
||||||
{
|
|
||||||
removeSize: true,
|
|
||||||
replaceColors: true,
|
|
||||||
addTransition: true,
|
|
||||||
},
|
|
||||||
{ rootViewBox: false },
|
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`compileSpriteContent` returns `Promise<Uint8Array>` and does not write to disk. `compileSprite(folder, outputDir, transform?, options?)` creates the output directory and writes `<folder.name>.sprite.svg`.
|
Values are applied as `defaults → config → API overrides`. `transform` is merged by field; a supplied `inputFiles` replaces the config array.
|
||||||
|
|
||||||
`CompileSpriteOptions.rootViewBox` defaults to `false`; the standard Next preset passes `true`, while React and legacy leave it `false`. Do not change this option in an attempt to replace the target: it does not determine how the asset is published.
|
The specialized `generateReactSprite` and `generateNextSprite` functions remain as compatibility wrappers, but prefer `generateSprite` in new code.
|
||||||
|
|
||||||
`resolveSpriteEntry` and `resolveSprites` resolve source paths relative to `process.cwd()`, verify existence, and read only the top level of a directory. They do not implement local `inputFolder + inputFiles` semantics; use the high-level generators for standard React/Next modules.
|
For custom orchestration, use `loadSpriteConfig`, `validateSpriteConfig`, `resolveSpriteConfig`, `compileSpriteContent`, and `createShapeTransform`.
|
||||||
|
|
||||||
`createShapeTransform(options)` returns a transform callback for `svg-sprite`. It is an integration primitive, not a `string -> string` function.
|
|
||||||
|
|
||||||
`generatePreview(results, outputDir)` expects every `results[].spritePath` to exist and writes `preview.html` from the package template. Do not invoke it before compilation.
|
|
||||||
|
|
||||||
## React debug runtime
|
|
||||||
|
|
||||||
The Viewer is exposed through a separate client entry:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|
||||||
import type {
|
|
||||||
SpriteManifest,
|
|
||||||
SpriteManifestLoader,
|
|
||||||
SpriteManifestModule,
|
|
||||||
SpriteViewerColorTheme,
|
|
||||||
SpriteViewerProps,
|
|
||||||
SpriteViewerSources,
|
|
||||||
} from '@gromlab/svg-sprites/react'
|
|
||||||
```
|
|
||||||
|
|
||||||
`SpriteViewerSources` accepts an array or record of manifests/loaders, including the result of Vite's `import.meta.glob`. A loader may return a manifest directly or a module with `default`/`spriteManifest`. An invalid module fails with `The loaded module does not export a valid SVG sprite manifest.`
|
|
||||||
|
|
||||||
The package React entry contains `'use client'`; do not import it from server-only build scripts or production icon modules. The generated production component lives in the selected sprite directory.
|
|
||||||
|
|
||||||
## Orchestrating multiple modules
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const roots = [
|
|
||||||
'src/ui/global/svg-sprite',
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
]
|
|
||||||
|
|
||||||
const results = await Promise.all(
|
|
||||||
roots.map((root) => generateReactSprite(root, 'vite')),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (results.some((result) => result.iconCount === 0)) {
|
|
||||||
throw new Error('Empty sprite module')
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not run different targets concurrently for one root: both calls own the same generated paths.
|
|
||||||
|
|
||||||
## Verification and error handling
|
|
||||||
|
|
||||||
Run programmatic generation and the project's typecheck; these are the required quick checks. After invocation, inspect `result.target`, `iconCount`, and the existence of `spritePath`/`manifestPath`. Add a real bundler build and browser/Network checks only when the target/pipeline changed or a runtime issue is being diagnosed; do not claim visual or accessibility results without the necessary tools.
|
|
||||||
|
|
||||||
Common failure causes:
|
|
||||||
|
|
||||||
- an unsupported target/router/bundler was passed as an unchecked string;
|
|
||||||
- `process.cwd()` differs in a monorepo runner, so a relative root points elsewhere;
|
|
||||||
- the config has no default export;
|
|
||||||
- an explicitly configured `inputFolder` is missing;
|
|
||||||
- two source files produce the same fragment ID;
|
|
||||||
- custom orchestration attempts to overwrite a user-owned file in a managed path;
|
|
||||||
- `generatePreview` cannot find its template when running from unbuilt package sources;
|
|
||||||
- a complex SVG requires individual transforms to be disabled according to [complex-svg.md](complex-svg.md).
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ Use this document when the project uses React without Next.js and is built with
|
|||||||
|
|
||||||
1. Check `package.json`: confirm React, Vite, and the actual `dev`, `build`, and `typecheck` commands.
|
1. Check `package.json`: confirm React, Vite, and the actual `dev`, `build`, and `typecheck` commands.
|
||||||
2. Find existing `svg-sprite.config.ts` files and scripts containing `svg-sprites`. Do not create a second directory for an existing sprite.
|
2. Find existing `svg-sprite.config.ts` files and scripts containing `svg-sprites`. Do not create a second directory for an existing sprite.
|
||||||
3. Choose a target directory for the specific sprite. It does not have to be a module or feature directory: the generator accepts the directory containing the config, not the config file or `icons/` path.
|
3. Choose a target directory for the specific sprite. It does not have to be a module or feature directory; pass the full path to its config file.
|
||||||
4. Do not manually edit `generated/`, `index.ts`, `manifest.ts`, or the local `.gitignore`; the generator owns them.
|
4. Do not manually edit `.svg-sprite` or the local `.gitignore`; the generator owns them. The root `index.ts` is application-owned.
|
||||||
|
|
||||||
Minimal structure:
|
Minimal structure:
|
||||||
|
|
||||||
@@ -32,9 +32,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -58,7 +59,7 @@ Add the local CLI to `package.json` and run it before processes that need genera
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -95,7 +96,7 @@ export const availableIcons = fileManagerIconNames
|
|||||||
<FileManagerIcon icon="folder" wrapped className="iconBox" />
|
<FileManagerIcon icon="folder" wrapped className="iconBox" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not deep-import from `generated/`; its file structure is not an integration point.
|
For normal imports, use a user-owned barrel with `export * from './.svg-sprite'`; the remaining files in the hidden directory are internal.
|
||||||
|
|
||||||
## Target-specific behavior
|
## Target-specific behavior
|
||||||
|
|
||||||
@@ -110,14 +111,14 @@ The `?no-inline` query is required: it prevents Vite from converting a small SVG
|
|||||||
Use the same mechanism for low-level `<use>` integration:
|
Use the same mechanism for low-level `<use>` integration:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
import spriteUrl from './svg-sprite/.svg-sprite/sprite.svg?no-inline'
|
||||||
|
|
||||||
<svg className="icon">
|
<svg className="icon">
|
||||||
<use href={`${spriteUrl}#check`} />
|
<use href={`${spriteUrl}#check`} />
|
||||||
</svg>
|
</svg>
|
||||||
```
|
```
|
||||||
|
|
||||||
A manual `#check` fragment is safe only for names matching `^[a-zA-Z][a-zA-Z0-9_-]*$`. For spaces and other characters, the generated component uses a stable hash ID; the exact ID is available in `manifest.ts`.
|
A manual `#check` fragment is safe only for names matching `^[a-zA-Z][a-zA-Z0-9_-]*$`. For spaces and other characters, the generated component uses a stable hash ID; the exact ID is available in `.svg-sprite/svg-sprite.manifest.js`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|||||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = import.meta.glob<SpriteManifestModule>(
|
const sources = import.meta.glob<SpriteManifestModule>(
|
||||||
'/src/**/svg-sprite/manifest.ts',
|
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
export function IconsDebugPage() {
|
export function IconsDebugPage() {
|
||||||
@@ -136,7 +137,7 @@ export function IconsDebugPage() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `import.meta.glob` argument must remain a string literal. Generation must finish before Vite starts, or new `manifest.ts` files will not be included in the glob.
|
The `import.meta.glob` argument must remain a string literal. Generation must finish before Vite starts, or new manifests will not be included in the glob.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
@@ -147,18 +148,18 @@ npm run typecheck
|
|||||||
|
|
||||||
These are the required quick checks. Inspect the generated files statically:
|
These are the required quick checks. Inspect the generated files statically:
|
||||||
|
|
||||||
- public `index.ts` exports the component, props, style, name union, and runtime array;
|
- the user-owned `index.ts` re-exports the component, props, style, name union, and runtime array from `.svg-sprite`;
|
||||||
- `manifest.ts` contains `target: "vite"`, `format: "stack"`, and the expected icon count.
|
- `.svg-sprite/svg-sprite.manifest.js` contains `target: "vite"`, `format: "stack"`, and the expected icon count.
|
||||||
|
|
||||||
If the target or asset pipeline changed, or a runtime issue is being diagnosed, also run the production build. When browser tools are available, inspect Network for a separate `.svg` asset rather than `data:image/svg+xml`, a successful URL, and `<use href="...svg#...">`. For complex colors, `defs`, and dimensions, follow [complex-svg.md](complex-svg.md); do not claim a visual or accessibility result without the necessary tools.
|
If the target or asset pipeline changed, or a runtime issue is being diagnosed, also run the production build. When browser tools are available, inspect Network for a separate `.svg` asset rather than `data:image/svg+xml`, a successful URL, and `<use href="...svg#...">`. For complex colors, `defs`, and dimensions, follow [complex-svg.md](complex-svg.md); do not claim a visual or accessibility result without the necessary tools.
|
||||||
|
|
||||||
## Common failures
|
## Common failures
|
||||||
|
|
||||||
- `React config file not found`: the command points to `icons/` or the config file; pass the directory containing `svg-sprite.config.ts`.
|
- Config not found: pass the full path to an existing `.ts`, `.js`, or `.json` config file.
|
||||||
- `React mode requires a target`: `--mode react` was used; the mode must be exactly `react@vite`.
|
- `Sprite mode is required`: set `mode: 'react@vite'` in the config or pass `--mode react@vite`.
|
||||||
- Icon missing from autocomplete: check the case-sensitive `.svg` suffix and shallow location, then regenerate before typechecking.
|
- Icon missing from autocomplete: check the case-sensitive `.svg` suffix and shallow location, then regenerate before typechecking.
|
||||||
- `Refusing to overwrite a user file`: do not remove the marker or bypass the writer; move the user-owned file or choose another sprite directory.
|
- `Refusing to overwrite a user file`: do not remove the marker or bypass the writer; move the user-owned file or choose another sprite directory.
|
||||||
- Viewer is empty: check the literal glob, the existence of generated `manifest.ts`, and the `predev` execution order.
|
- Viewer is empty: check the literal glob, the existence of `.svg-sprite/svg-sprite.manifest.js`, and the `predev` execution order.
|
||||||
- SVG was inlined: confirm that the module targets `vite` and its import still contains `?no-inline`.
|
- SVG was inlined: confirm that the module targets `vite` and its import still contains `?no-inline`.
|
||||||
- TypeScript cannot resolve the package subpath: use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
- TypeScript cannot resolve the package subpath: use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Use this document for a React application built with Webpack 5 when SVGs must be
|
|||||||
1. Confirm Webpack major version 5 in `package.json` or the lockfile.
|
1. Confirm Webpack major version 5 in `package.json` or the lockfile.
|
||||||
2. Inspect `.svg` entries in `module.rules`, `output.publicPath`, the dev server, and existing asset conventions.
|
2. Inspect `.svg` entries in `module.rules`, `output.publicPath`, the dev server, and existing asset conventions.
|
||||||
3. Find existing `svg-sprite.config.ts` files and generation scripts.
|
3. Find existing `svg-sprite.config.ts` files and generation scripts.
|
||||||
4. Choose the project directory for the specific sprite. It does not have to match a module or feature directory. The command accepts the directory containing the config, not the config file or icons folder.
|
4. Choose the project directory for the specific sprite. It does not have to match a module or feature directory. Pass the full path to its config file.
|
||||||
|
|
||||||
Minimal structure:
|
Minimal structure:
|
||||||
|
|
||||||
@@ -30,9 +30,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'File manager icons',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -49,7 +50,7 @@ Recommended lifecycle hooks:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -74,7 +75,7 @@ export function OpenFolderButton() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`width` and `height` are optional in JSX; set the size with a CSS class or `wrapped`. The public entry point also exports `FileManagerIconProps`, `FileManagerIconStyle`, `FileManagerIconName`, and `fileManagerIconNames`. Do not import files directly from `generated/`, and do not edit `generated/`, `index.ts`, `manifest.ts`, or the generated `.gitignore`.
|
`width` and `height` are optional in JSX; set the size with a CSS class or `wrapped`. The user-owned barrel also exports `FileManagerIconProps`, `FileManagerIconStyle`, `FileManagerIconName`, and `fileManagerIconNames`. Do not edit `.svg-sprite` or the generated `.gitignore`.
|
||||||
|
|
||||||
## Webpack target behavior
|
## Webpack target behavior
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ Webpack 5 recognizes it as an Asset Module and replaces it with the public URL o
|
|||||||
|
|
||||||
- do not move the path into a variable or modify the generated expression;
|
- do not move the path into a variable or modify the generated expression;
|
||||||
- ensure Babel/TypeScript does not transform `import.meta.url` before Webpack processes it;
|
- ensure Babel/TypeScript does not transform `import.meta.url` before Webpack processes it;
|
||||||
- do not let `@svgr/webpack`, `svg-inline-loader`, `raw-loader`, or a general SVG rule intercept `svg-sprite/generated/sprite.svg`;
|
- do not let `@svgr/webpack`, `svg-inline-loader`, `raw-loader`, or a general SVG rule intercept `svg-sprite/.svg-sprite/sprite.svg`;
|
||||||
- with custom rules, either exclude the generated sprite from component/raw loaders or add a dedicated `type: 'asset/resource'` rule;
|
- with custom rules, either exclude the generated sprite from component/raw loaders or add a dedicated `type: 'asset/resource'` rule;
|
||||||
- check `output.publicPath`, especially for CDN, subpath, and dev-server deployments.
|
- check `output.publicPath`, especially for CDN, subpath, and dev-server deployments.
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ Example dedicated rule when an existing loader intercepts every SVG:
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
test: /svg-sprite[\\/]generated[\\/]sprite\.svg$/,
|
test: /svg-sprite[\\/]\.svg-sprite[\\/]sprite\.svg$/,
|
||||||
type: 'asset/resource',
|
type: 'asset/resource',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -131,7 +132,7 @@ npm run typecheck
|
|||||||
|
|
||||||
These are the required quick checks. After generation, verify that:
|
These are the required quick checks. After generation, verify that:
|
||||||
|
|
||||||
- `manifest.ts` contains `target: "webpack"` and `format: "stack"`;
|
- `.svg-sprite/svg-sprite.manifest.js` contains `target: "webpack"` and `format: "stack"`;
|
||||||
- the generated component contains `new URL('./sprite.svg', import.meta.url).href`.
|
- the generated component contains `new URL('./sprite.svg', import.meta.url).href`.
|
||||||
|
|
||||||
A production build and browser/Network checks are additionally required when the target, Webpack asset rules, `publicPath`/deployment pipeline changed, or a runtime issue is being diagnosed. In that case, verify a separate hashed SVG asset, an HTTP(S) `.svg#id` URL, content type, fragment ID, and the correct CDN/subpath URL. Do not claim visual or accessibility correctness without the necessary tools.
|
A production build and browser/Network checks are additionally required when the target, Webpack asset rules, `publicPath`/deployment pipeline changed, or a runtime issue is being diagnosed. In that case, verify a separate hashed SVG asset, an HTTP(S) `.svg#id` URL, content type, fragment ID, and the correct CDN/subpath URL. Do not claim visual or accessibility correctness without the necessary tools.
|
||||||
@@ -145,7 +146,7 @@ For icons with gradients, filters, masks, or internal CSS, perform the checks in
|
|||||||
- URL points to the wrong host/subpath: fix `output.publicPath` and runtime deployment settings, not the generated file.
|
- URL points to the wrong host/subpath: fix `output.publicPath` and runtime deployment settings, not the generated file.
|
||||||
- `import.meta` is unsupported: confirm the build really uses Webpack 5 and that an intermediate transpiler preserves the expression.
|
- `import.meta` is unsupported: confirm the build really uses Webpack 5 and that an intermediate transpiler preserves the expression.
|
||||||
- Viewer does not load the manifest: check the literal path, chunk loading, and generation before compilation.
|
- Viewer does not load the manifest: check the literal path, chunk loading, and generation before compilation.
|
||||||
- `Refusing to overwrite a user file`: the directory already contains a user-owned `index.ts`, `manifest.ts`, `.gitignore`, or file in `generated/`; move it rather than bypassing protection.
|
- `Refusing to overwrite a user file`: the directory already contains a user-owned `.gitignore` or file in `.svg-sprite`; move it rather than bypassing protection.
|
||||||
- Icon color does not change: use `color` for monochrome icons or `--icon-color-N` through `<svg><use>`; page CSS does not cross into `<img>`.
|
- Icon color does not change: use `color` for monochrome icons or `--icon-color-N` through `<svg><use>`; page CSS does not cross into `<img>`.
|
||||||
|
|
||||||
For custom build orchestration, see [programmatic-api.md](programmatic-api.md).
|
For custom build orchestration, see [programmatic-api.md](programmatic-api.md).
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
- Для React + Vite открой [React + Vite](./references/react-vite.md), для React с собственным Webpack 5 — [React + Webpack](./references/react-webpack.md).
|
- Для React + Vite открой [React + Vite](./references/react-vite.md), для React с собственным Webpack 5 — [React + Webpack](./references/react-webpack.md).
|
||||||
- Для Next.js открой руководство для [App Router](./references/next-app.md) или [Pages Router](./references/next-pages.md) и выбери раздел фактического сборщика.
|
- Для Next.js открой руководство для [App Router](./references/next-app.md) или [Pages Router](./references/next-pages.md) и выбери раздел фактического сборщика.
|
||||||
- При `svg-sprites.config.ts` открой [legacy mode](./references/legacy.md); при переходе с `0.1.x` дополнительно открой [миграцию](./references/migration-1.md).
|
|
||||||
- Для вызова генератора из Node.js открой [программный API](./references/programmatic-api.md).
|
- Для вызова генератора из Node.js открой [программный API](./references/programmatic-api.md).
|
||||||
- Для gradients, filters, `url(#...)`, нестандартных цветов и проблем с `viewBox` открой [сложные SVG](./references/complex-svg.md).
|
- Для gradients, filters, `url(#...)`, нестандартных цветов и проблем с `viewBox` открой [сложные SVG](./references/complex-svg.md).
|
||||||
- Полную пользовательскую документацию используй как вторичный источник: [README пакета](./references/upstream/README_RU.md).
|
- Полную пользовательскую документацию используй как вторичный источник: [README пакета](./references/upstream/README_RU.md).
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
`@gromlab/svg-sprites` — CLI-генератор SVG-спрайтов для пользовательских SVG-файлов. Пакет не содержит собственного набора иконок: он собирает SVG проекта во внешний кешируемый sprite asset и для React/Next.js создаёт типизированный компонент, список допустимых имён и debug manifest.
|
`@gromlab/svg-sprites` — CLI-генератор SVG-спрайтов для пользовательских SVG-файлов. Пакет не содержит собственного набора иконок: он собирает SVG проекта во внешний кешируемый sprite asset и для React/Next.js создаёт типизированный компонент, список допустимых имён и debug manifest.
|
||||||
|
|
||||||
Пакет рассчитан на несколько независимых спрайтов в одном проекте. Каждый выбранный каталог с `svg-sprite.config.ts` описывает один спрайт и получает собственные:
|
Пакет рассчитан на несколько независимых спрайтов в одном проекте. Каждый явно выбранный config-файл или config-less каталог описывает один спрайт и получает собственные:
|
||||||
|
|
||||||
- SVG asset;
|
- SVG asset;
|
||||||
- типы имён иконок;
|
- типы имён иконок;
|
||||||
- React-компонент;
|
- React-компонент;
|
||||||
- production entry `index.ts`;
|
- production entry `.svg-sprite/index.js` с `.d.ts`;
|
||||||
- debug entry `manifest.ts`.
|
- debug entry `.svg-sprite/svg-sprite.manifest.js` с `.d.ts`.
|
||||||
|
|
||||||
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Имена `FileManagerIcon` и `fileManagerIconNames` ниже являются примерами API одного из возможных спрайтов, а не фиксированными экспортами пакета.
|
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Имена `FileManagerIcon` и `fileManagerIconNames` ниже являются примерами API одного из возможных спрайтов, а не фиксированными экспортами пакета.
|
||||||
|
|
||||||
|
|||||||
@@ -10,24 +10,18 @@
|
|||||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||||
| Старый общий конфиг | `legacy` |
|
|
||||||
|
|
||||||
Не используй неполные `react`, `next@app`, `next@pages`, будущий `standalone` или mode другого сборщика. Установи пакет как development dependency и добавь локальный CLI в package script. CLI всегда требует mode и ровно один путь к каталогу конфигурации:
|
Mode задаётся в config, CLI или программном API. Порядок применения: `defaults → config → CLI/API overrides`. После объединения mode обязателен.
|
||||||
|
|
||||||
|
CLI принимает ровно один путь. Путь к файлу `.ts`, `.js` или `.json` загружает именно этот конфиг независимо от имени. Путь к каталогу включает config-less генерацию, и настройки передаются флагами CLI.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:<name>": "svg-sprites --mode <mode-key> <sprite-directory>"
|
"sprite:<name>": "svg-sprites <path-to-config>",
|
||||||
|
"sprite:<name>:cli": "svg-sprites --mode <mode-key> <sprite-directory>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Не передавай несколько путей, glob или путь к самому файлу конфигурации. Для нескольких современных спрайтов создай отдельную команду для каждого каталога.
|
Не используй неполные `react`, `next@app`, `next@pages`, удалённый `legacy` или ещё не реализованный `standalone`. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.
|
||||||
|
|
||||||
Определяй legacy по контракту, а не по количеству спрайтов:
|
|
||||||
|
|
||||||
- `svg-sprites.config.ts` в переданном корне с верхнеуровневыми `output` и непустым массивом `sprites` является legacy-конфигурацией даже при одном элементе;
|
|
||||||
- каждый legacy-элемент использует `name`, `input` и необязательный `format: 'stack' | 'symbol'`; поле `mode` устарело;
|
|
||||||
- локальный `svg-sprite.config.ts` в каталоге одного спрайта с `name`, `description`, `inputFolder`, `inputFiles`, `transform` и `generatedNotice` относится к React/Next API даже если таких спрайтов в приложении много.
|
|
||||||
|
|
||||||
Не мигрируй legacy-конфигурацию без явного запроса. Не смешивай `defineLegacyConfig` и поля `output`/`sprites` с `defineReactSpriteConfig` или `defineNextSpriteConfig`.
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
До изменений установи фактический контракт проекта:
|
До изменений установи фактический контракт проекта:
|
||||||
|
|
||||||
1. Прочитай корневой `package.json`, lock-файл и workspace-конфигурацию; определи framework, bundler и существующие команды.
|
1. Прочитай корневой `package.json`, lock-файл и workspace-конфигурацию; определи framework, bundler и существующие команды.
|
||||||
2. Найди `svg-sprite.config.ts`, `svg-sprites.config.ts`, команды `svg-sprites` и импорты generated-компонентов.
|
2. Найди config-файлы, команды `svg-sprites` и импорты generated-компонентов. Имя конфига произвольное; ориентируйся на переданный CLI путь и поля объекта.
|
||||||
3. Для React определи Vite или Webpack 5 по scripts и конфигу. Для Next.js отдельно определи App/Pages Router и сборщик реальных `dev`/`build` команд.
|
3. Для React определи Vite или Webpack 5 по scripts и конфигу. Для Next.js отдельно определи App/Pages Router и сборщик реальных `dev`/`build` команд.
|
||||||
4. Проверь существующие `predev`, `prebuild`, `pretypecheck` и агрегирующие scripts. Не перезаписывай их.
|
4. Проверь существующие `predev`, `prebuild`, `pretypecheck` и агрегирующие scripts. Не перезаписывай их.
|
||||||
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
|
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
|
||||||
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
|
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
|
||||||
|
|
||||||
Все пути современного конфига считаются относительно каталога, содержащего `svg-sprite.config.ts`:
|
Все пути конфига считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога:
|
||||||
|
|
||||||
- `inputFolder` по умолчанию равен `./icons`;
|
- `inputFolder` по умолчанию равен `./icons`;
|
||||||
- `inputFiles` содержит дополнительные относительные пути к отдельным SVG и объединяется с `inputFolder`;
|
- `inputFiles` содержит дополнительные относительные пути к отдельным SVG и объединяется с `inputFolder`;
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
Используй config helper для autocomplete и проверки типов:
|
Используй config helper для autocomplete и проверки типов:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -31,7 +32,7 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Контракт объекта одинаков для React и Next.js. Для Next.js-спрайта используй `defineNextSpriteConfig(...)`.
|
Контракт объекта одинаков для React и Next.js; отличается полный `mode`.
|
||||||
|
|
||||||
`name` должен начинаться с латинской буквы и записываться в kebab-case; из примера `file-manager` будут созданы `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`. Другой спрайт получает собственные имена. Если `name` не задан, генератор выводит его из каталога.
|
`name` должен начинаться с латинской буквы и записываться в kebab-case; из примера `file-manager` будут созданы `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`. Другой спрайт получает собственные имена. Если `name` не задан, генератор выводит его из каталога.
|
||||||
|
|
||||||
@@ -40,15 +41,15 @@ export default defineReactSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"sprites": "npm run sprite:file-manager"
|
"sprites": "npm run sprite:file-manager"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Для Next.js подставь полный ключ, например `next@app/turbopack`. Для нескольких спрайтов добавь по команде `sprite:<name>` на каждый каталог и последовательно вызови их из `sprites`.
|
Для Next.js укажи в config полный ключ, например `next@app/turbopack`. Для нескольких спрайтов добавь по команде `sprite:<name>` на каждый config-файл и последовательно вызови их из `sprites`.
|
||||||
|
|
||||||
Generated-файлы по умолчанию исключаются из Git, поэтому запускай `sprites` до процессов, которым нужны `index.ts`, типы или asset. Добавь вызов к `predev`, `prebuild` и, если есть `typecheck`, к `pretypecheck`.
|
Generated-файлы в `.svg-sprite` по умолчанию исключаются из Git, поэтому запускай `sprites` до процессов, которым нужны компонент, типы или asset. Если проект импортирует корень sprite-модуля, создай пользовательский `index.ts` с `export * from './.svg-sprite'`. Добавь генерацию к `predev`, `prebuild` и, если есть `typecheck`, к `pretypecheck`.
|
||||||
|
|
||||||
Если lifecycle script отсутствует, создай его. Если он уже существует, сохрани его команду и допиши генерацию через `&&`, например преобразуй `"prebuild": "npm run lint"` в `"prebuild": "npm run lint && npm run sprites"`. Никогда не заменяй существующий `pre*` одной генерацией и не создавай второй одноимённый JSON key.
|
Если lifecycle script отсутствует, создай его. Если он уже существует, сохрани его команду и допиши генерацию через `&&`, например преобразуй `"prebuild": "npm run lint"` в `"prebuild": "npm run lint && npm run sprites"`. Никогда не заменяй существующий `pre*` одной генерацией и не создавай второй одноимённый JSON key.
|
||||||
|
|
||||||
|
|||||||
@@ -5,23 +5,33 @@
|
|||||||
```text
|
```text
|
||||||
svg-sprite/
|
svg-sprite/
|
||||||
├── icons/ # пользовательские исходники
|
├── icons/ # пользовательские исходники
|
||||||
├── svg-sprite.config.ts # пользовательский конфиг
|
├── svg-sprite.config.ts # рекомендуемое имя конфига
|
||||||
|
├── index.ts # необязательный пользовательский barrel
|
||||||
├── .gitignore # управляет генератор
|
├── .gitignore # управляет генератор
|
||||||
├── index.ts # публичная production-точка входа
|
└── .svg-sprite/
|
||||||
├── manifest.ts # отдельная debug-точка входа
|
├── state.json # реестр владения и версия контракта
|
||||||
└── generated/
|
├── index.js
|
||||||
├── .svg-sprites.manifest.json # реестр владения
|
├── index.d.ts
|
||||||
├── react-component.tsx
|
├── icon-data.js
|
||||||
|
├── icon-data.d.ts
|
||||||
├── sprite.svg
|
├── sprite.svg
|
||||||
├── styles.module.css
|
├── svg-sprite.manifest.js
|
||||||
└── types.ts
|
├── svg-sprite.manifest.d.ts
|
||||||
|
└── react/
|
||||||
|
├── react-component.js
|
||||||
|
├── react-component.d.ts
|
||||||
|
└── react-component.module.css
|
||||||
```
|
```
|
||||||
|
|
||||||
Редактируй только исходные SVG и `svg-sprite.config.ts`. Не изменяй вручную `.gitignore`, `index.ts`, `manifest.ts` и содержимое `generated/`: повторная генерация их перезапишет. Импортируй production API из корневого `index.ts`, а не deep import из `generated/`.
|
Редактируй исходные SVG, config-файл и пользовательский `index.ts`. Не изменяй вручную `.gitignore` и содержимое `.svg-sprite`: повторная генерация их перезапишет. Для импорта из корня sprite-модуля создай barrel:
|
||||||
|
|
||||||
Генератор владеет только перечисленными корневыми файлами и непосредственными файлами `generated/`. Реестр `.svg-sprites.manifest.json` позволяет удалить устаревший generated-файл, но writer откажется перезаписывать или удалять файл без generated-маркера. Не удаляй маркер, не обходи отказ и не подменяй generated-пути symlink: перенеси пользовательский файл или выбери другой каталог.
|
```ts
|
||||||
|
export * from './.svg-sprite'
|
||||||
|
```
|
||||||
|
|
||||||
Публичная точка входа экспортирует компонент, props/style-типы, readonly-массив имён и union-тип имени. `manifest.ts` содержит URL, target, список и метаданные иконок для debug-инструментов и не импортируется production-компонентом.
|
Генератор владеет `.gitignore` и файлами внутри `.svg-sprite`. Реестр `state.json` позволяет удалить устаревший generated-файл, но writer откажется перезаписывать или удалять файл без generated-маркера. Не удаляй маркер, не обходи отказ и не подменяй generated-пути symlink: перенеси пользовательский файл или выбери другой каталог.
|
||||||
|
|
||||||
|
Внутренний `index.js` экспортирует компонент из `react/react-component.js` и readonly-массив имён; соседний `index.d.ts` добавляет props/style-типы и union имени. Manifest содержит mode, URL, target, список и метаданные иконок для debug-инструментов и не импортируется production-компонентом.
|
||||||
|
|
||||||
Спрайт остаётся отдельным asset с content hash; SVG path-данные не встраиваются в JavaScript:
|
Спрайт остаётся отдельным asset с content hash; SVG path-данные не встраиваются в JavaScript:
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ Generated-компонент не выбирает семантику за пр
|
|||||||
|
|
||||||
`SpriteViewer` необязателен. Подключай его из `@gromlab/svg-sprites/react` только на debug-маршруте:
|
`SpriteViewer` необязателен. Подключай его из `@gromlab/svg-sprites/react` только на debug-маршруте:
|
||||||
|
|
||||||
- в Vite передай результат строкового literal `import.meta.glob('/src/**/svg-sprite/manifest.ts')`;
|
- в Vite передай результат строкового literal `import.meta.glob('/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js')`;
|
||||||
- в Webpack передай массив статических `() => import('.../manifest')`;
|
- в Webpack передай массив статических `() => import('.../manifest')`;
|
||||||
- в Next.js используй такие же статические loaders, а для App Router помести Viewer в отдельный файл с `'use client'`.
|
- в Next.js используй такие же статические loaders, а для App Router помести Viewer в отдельный файл с `'use client'`.
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
После изменения конфига или SVG выполни обязательные быстрые проверки:
|
После изменения конфига или SVG выполни обязательные быстрые проверки:
|
||||||
|
|
||||||
1. Запусти точную sprite-команду, например `npm run sprite:file-manager`; процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `generated`.
|
1. Запусти точную sprite-команду, например `npm run sprite:file-manager`; процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `.svg-sprite`.
|
||||||
2. Проверь наличие `index.ts`, `manifest.ts`, `generated/sprite.svg`, `generated/react-component.tsx`, `generated/types.ts`, `generated/styles.module.css` и `generated/.svg-sprites.manifest.json`.
|
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, а также `state.json`.
|
||||||
3. Убедись, что новая иконка присутствует в readonly-массиве имён и принимается prop `icon`.
|
3. Убедись, что новая иконка присутствует в readonly-массиве имён и принимается prop `icon`.
|
||||||
4. Запусти существующую проверку типов проекта, например `npm run typecheck`.
|
4. Запусти существующую проверку типов проекта, например `npm run typecheck`.
|
||||||
5. Проверь в `manifest.ts`, что `target` совпадает с выбранным mode key; generated asset expression должен быть `?no-inline` для Vite и `new URL(...)` для Webpack/Next.
|
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.
|
Не запускай полную production-сборку только ради проверки изменения списка иконок. Она нужна, если менялся bundler target, конфигурация asset pipeline, Next router/bundler, Webpack loader или диагностируется ошибка URL в runtime.
|
||||||
|
|
||||||
|
|||||||
@@ -4,21 +4,20 @@
|
|||||||
|
|
||||||
| Симптом | Вероятная причина | Действие |
|
| Симптом | Вероятная причина | Действие |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `Missing required argument: --mode` или `Missing sprite path` | Неполная CLI-команда | Передай `--mode <полный-key>` и один каталог спрайта. |
|
| `Missing sprite config file or module directory` | Не передан позиционный путь | Передай один config-файл либо каталог для config-less запуска. |
|
||||||
| `Expected one sprite path` | Передано несколько путей | Создай отдельную команду на каждый современный спрайт и объедини scripts. |
|
| `Expected one config file or module directory` | Передано несколько путей | Создай отдельную команду на каждый спрайт и объедини scripts. |
|
||||||
| `React mode requires a target` или `Unsupported Next.js target` | Использован сокращённый/неподдерживаемый key | Выбери один из семи mode keys из таблицы, не используй `standalone`. |
|
| `Sprite mode is required` | Mode отсутствует и в config, и в CLI | Добавь `mode` в объект или передай полный `--mode`. |
|
||||||
| `React config file not found` | CLI указывает не на каталог с `svg-sprite.config.ts` | Исправь позиционный путь; не передавай путь к файлу. |
|
| `Unsupported sprite config extension` | Передан файл не `.ts`, `.js` или `.json` | Используй поддерживаемый формат config-файла. |
|
||||||
| Legacy config не найден или читается не тем pipeline | Перепутаны `svg-sprites.config.ts` и `svg-sprite.config.ts` | Определи API по имени и полям конфига, независимо от числа элементов `sprites`. |
|
|
||||||
| `Input directory does not exist` | Ошибка относительного пути или отсутствует явно заданная папка | Считай путь от каталога конфига; создай папку или исправь `inputFolder`. |
|
| `Input directory does not exist` | Ошибка относительного пути или отсутствует явно заданная папка | Считай путь от каталога конфига; создай папку или исправь `inputFolder`. |
|
||||||
| Иконки из подпапки не появились | Ожидался recursive scan | Перемести SVG на верхний уровень `inputFolder` или перечисли его в `inputFiles`. |
|
| Иконки из подпапки не появились | Ожидался recursive scan | Перемести SVG на верхний уровень `inputFolder` или перечисли его в `inputFiles`. |
|
||||||
| `SVG file does not exist`, `File is not an SVG` или пустой набор | Неверный `inputFiles`, расширение или источники | Исправь путь/расширение и обеспечь хотя бы один входной SVG. |
|
| `SVG file does not exist`, `File is not an SVG` или пустой набор | Неверный `inputFiles`, расширение или источники | Исправь путь/расширение и обеспечь хотя бы один входной SVG. |
|
||||||
| Конфликт имени иконки или SVG ID | Два разных файла имеют одинаковый basename либо hash-ID столкнулся с именем | Переименуй один исходный SVG; не выбирай файл неявно. |
|
| Конфликт имени иконки или SVG ID | Два разных файла имеют одинаковый basename либо hash-ID столкнулся с именем | Переименуй один исходный SVG; не выбирай файл неявно. |
|
||||||
| `Refusing to overwrite/delete a user file` | Пользовательский файл занял managed-путь или потерял marker | Не обходи защиту: перенеси файл либо выбери другой sprite-каталог и перегенерируй. |
|
| `Refusing to overwrite/delete a user file` | Пользовательский файл занял managed-путь или потерял marker | Не обходи защиту: перенеси файл либо выбери другой sprite-каталог и перегенерируй. |
|
||||||
| Нет `index.ts` или имя отсутствует в autocomplete | Генерация не запускалась после изменения либо type server держит старый модуль | Запусти sprite-команду, затем typecheck; при необходимости перезапусти TypeScript server. |
|
| Нет `.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. |
|
| 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 и перегенерируй. |
|
| Next build расходится между SSR и браузером | Модуль сгенерирован для другого bundler/router или URL переписан вручную | Верни generated `new URL(...)`, выбери точный Next mode и перегенерируй. |
|
||||||
| `color` не меняет многоцветную иконку | У иконки несколько переменных или она показана через `<img>`/CSS background | Используй `<FileManagerIcon>`/`<svg><use>` и нужные `--icon-color-N`. |
|
| `color` не меняет многоцветную иконку | У иконки несколько переменных или она показана через `<img>`/CSS background | Используй `<FileManagerIcon>`/`<svg><use>` и нужные `--icon-color-N`. |
|
||||||
| Gradient/filter выглядит неверно | Автозамена цветов не гарантирует сложные paint servers | Изучи generated SVG; при необходимости отключи `replaceColors` для спрайта или упрости источник. |
|
| Gradient/filter выглядит неверно | Автозамена цветов не гарантирует сложные paint servers | Изучи generated SVG; при необходимости отключи `replaceColors` для спрайта или упрости источник. |
|
||||||
| Viewer пуст | Манифесты не созданы, glob/import не статический или неверен Client Component boundary | Сначала сгенерируй спрайты; для Vite используй literal glob, для Webpack/Next статические loaders, для App Router добавь `'use client'` только Viewer-странице. |
|
| Viewer пуст | Манифесты не созданы, glob/import не статический или неверен Client Component boundary | Сначала сгенерируй спрайты; для Vite используй literal glob, для Webpack/Next статические loaders, для App Router добавь `'use client'` только Viewer-странице. |
|
||||||
|
|
||||||
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к конфигу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и защитные markers.
|
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к config-файлу или каталогу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и защитные markers.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
npm run sprite:file-manager
|
npm run sprite:file-manager
|
||||||
```
|
```
|
||||||
|
|
||||||
Используй фактический package script нужного спрайта. Затем сравни source с `generated/sprite.svg` и manifest, не делая вывод только по успешному exit code.
|
Используй фактический package script нужного спрайта. Затем сравни source с `.svg-sprite/sprite.svg` и manifest, не делая вывод только по успешному exit code.
|
||||||
|
|
||||||
Особого внимания требуют:
|
Особого внимания требуют:
|
||||||
|
|
||||||
@@ -36,9 +36,10 @@ npm run sprite:file-manager
|
|||||||
Все три опции по умолчанию `true` и применяются ко всему спрайту, не к отдельной иконке.
|
Все три опции по умолчанию `true` и применяются ко всему спрайту, не к отдельной иконке.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'illustrations',
|
name: 'illustrations',
|
||||||
transform: {
|
transform: {
|
||||||
removeSize: false,
|
removeSize: false,
|
||||||
@@ -48,7 +49,7 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Это config для одного из потенциально многих проектов спрайтов; его каталог не обязан совпадать с module/feature-каталогом. Для Next используй `defineNextSpriteConfig(...)` с тем же `transform`; для legacy он находится на верхнем уровне `defineLegacyConfig(...)`.
|
Это config для одного из потенциально многих sprite-модулей; его каталог не обязан совпадать с module/feature-каталогом. Для Next укажи соответствующий полный `mode` с тем же `transform`.
|
||||||
|
|
||||||
## Размеры и viewBox
|
## Размеры и viewBox
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ export default defineReactSpriteConfig({
|
|||||||
|
|
||||||
Если физические размеры являются частью контракта иллюстрации, установи `removeSize: false` и проверь поведение component props. Не используй сохранение width/height как замену отсутствующему viewBox.
|
Если физические размеры являются частью контракта иллюстрации, установи `removeSize: false` и проверь поведение component props. Не используй сохранение width/height как замену отсутствующему viewBox.
|
||||||
|
|
||||||
React и legacy compile оставляют root sprite `rootViewBox` выключенным; Next включает его. У каждой shape всё равно должен быть собственный корректный viewBox, который попадает в manifest и используется Viewer.
|
React compile оставляет root sprite `rootViewBox` выключенным; Next включает его. У каждой shape всё равно должен быть собственный корректный viewBox, который попадает в manifest и используется Viewer.
|
||||||
|
|
||||||
## Цвета
|
## Цвета
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ transform: {
|
|||||||
<FileManagerIcon icon="folder open" />
|
<FileManagerIcon icon="folder open" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Не создавай вручную `#folder open`. Используй generated component либо `manifest.ts`, где записаны `name` и фактический `id`.
|
Не создавай вручную `#folder open`. Используй generated component либо `.svg-sprite/svg-sprite.manifest.js`, где записаны `name` и фактический `id`.
|
||||||
|
|
||||||
Разные файлы с одинаковым basename запрещены даже из разных directories. Переименуй один source осмысленно; порядок `inputFiles` не является способом выбрать победителя.
|
Разные файлы с одинаковым basename запрещены даже из разных directories. Переименуй один source осмысленно; порядок `inputFiles` не является способом выбрать победителя.
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ External stack fragment support и поведение paint servers могут
|
|||||||
3. Открой generated sprite и найди shape по ID из manifest.
|
3. Открой generated sprite и найди shape по ID из manifest.
|
||||||
4. Статически сверь `viewBox`, IDs, `url(#...)`, colors и inline styles.
|
4. Статически сверь `viewBox`, IDs, `url(#...)`, colors и inline styles.
|
||||||
5. Если менялись target/pipeline или диагностируется runtime, собери production bundle и проверь внешний hashed SVG.
|
5. Если менялись target/pipeline или диагностируется runtime, собери production bundle и проверь внешний hashed SVG.
|
||||||
6. При наличии SpriteViewer, legacy `preview.html` и визуальных инструментов проверь default colors и каждую `--icon-color-N` отдельно.
|
6. При наличии SpriteViewer и визуальных инструментов проверь default colors и каждую `--icon-color-N` отдельно.
|
||||||
7. При наличии browser-инструментов и соответствующем runtime-риске проверь SSR/hydration для Next.js и целевые browsers для external fragments.
|
7. При наличии browser-инструментов и соответствующем runtime-риске проверь SSR/hydration для Next.js и целевые browsers для external fragments.
|
||||||
8. Не утверждай визуальную или a11y эквивалентность source и результата без доступных инструментов и фактического сравнения.
|
8. Не утверждай визуальную или a11y эквивалентность source и результата без доступных инструментов и фактического сравнения.
|
||||||
|
|
||||||
@@ -172,4 +173,4 @@ External stack fragment support и поведение paint servers могут
|
|||||||
- Ручной fragment не работает для имени с пробелом: используй ID из manifest.
|
- Ручной fragment не работает для имени с пробелом: используй ID из manifest.
|
||||||
- Один сложный icon требует иных transforms: вынеси его в отдельный sprite; per-icon transform config отсутствует.
|
- Один сложный icon требует иных transforms: вынеси его в отдельный sprite; per-icon transform config отсутствует.
|
||||||
|
|
||||||
Target-specific запуск и проверка описаны в [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md), [next-pages.md](next-pages.md) и [legacy.md](legacy.md).
|
Target-specific запуск и проверка описаны в [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md) и [next-pages.md](next-pages.md).
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
# Legacy mode: операционный reference
|
|
||||||
|
|
||||||
## Когда открывать
|
|
||||||
|
|
||||||
Открывай этот документ, если проект уже использует корневой `svg-sprites.config.ts`, централизованный output, несколько записей `sprites`, формат `symbol` или автономный `preview.html`. Не мигрируй такой проект на локальные React/Next modules без явного запроса; для плановой миграции открой [migration-1.md](migration-1.md).
|
|
||||||
|
|
||||||
## Что отличает legacy
|
|
||||||
|
|
||||||
- Один config управляет одним или несколькими спрайтами.
|
|
||||||
- Результаты записываются как `<name>.sprite.svg` в общий `output`.
|
|
||||||
- Поддерживаются `stack` и `symbol`; default format равен `stack`.
|
|
||||||
- `preview` по умолчанию включён и создаёт общий `preview.html`.
|
|
||||||
- Нет generated React-компонента, manifest-модуля, локального `.gitignore` и защиты managed writer.
|
|
||||||
- Legacy paths в загруженном конфиге разрешаются относительно каталога, переданного CLI.
|
|
||||||
|
|
||||||
## Конфиг и запуск
|
|
||||||
|
|
||||||
Установи пакет как development dependency:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
`svg-sprites.config.ts`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineLegacyConfig({
|
|
||||||
output: 'public/sprites',
|
|
||||||
preview: true,
|
|
||||||
transform: {
|
|
||||||
removeSize: true,
|
|
||||||
replaceColors: true,
|
|
||||||
addTransition: true,
|
|
||||||
},
|
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'logos',
|
|
||||||
input: [
|
|
||||||
'src/assets/logos/product.svg',
|
|
||||||
'src/assets/shared/brand.svg',
|
|
||||||
],
|
|
||||||
format: 'stack',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
В отличие от локальных React/Next config, каждый из которых описывает один из потенциально многих спрайтов, один legacy config сохраняет специфическую возможность управлять одним или несколькими entries спрайтов.
|
|
||||||
|
|
||||||
Script:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy .",
|
|
||||||
"prebuild": "npm run sprites"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Запусти `npm run sprites` из project root.
|
|
||||||
|
|
||||||
CLI path указывает каталог с `svg-sprites.config.ts`. Не передавай сам файл. Для config в другом каталоге передай этот каталог явно.
|
|
||||||
|
|
||||||
## Семантика input
|
|
||||||
|
|
||||||
- Строковый `input` означает каталог; читаются только SVG первого уровня, отсортированные по имени.
|
|
||||||
- Массив `input` означает точный список файлов; пустой массив является ошибкой.
|
|
||||||
- Расширение проверяется case-sensitive по окончанию `.svg`.
|
|
||||||
- Для массива проверяется существование каждого файла.
|
|
||||||
- В отличие от локального React config, legacy entry не объединяет одновременно папку и список. Для смешанного набора перечисли все файлы либо раздели entries.
|
|
||||||
- `name` используется непосредственно в имени output-файла; выбирай уникальные безопасные имена и не создавай две entries с одинаковым output name.
|
|
||||||
|
|
||||||
## Выбор формата и runtime
|
|
||||||
|
|
||||||
`symbol` нужен для существующей интеграции через `<svg><use>`:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg width="24" height="24" aria-label="Готово">
|
|
||||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
|
||||||
</svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
`stack` подходит для `<svg><use>`, `<img src="...svg#check">` и CSS URL. Для нового React/Next-кода не строй local component поверх legacy output автоматически: сначала выбери соответствующий современный mode.
|
|
||||||
|
|
||||||
CSS custom properties страницы управляют содержимым при `<svg><use>`, но не проникают в документ, загруженный как `<img>` или `background-image`. `symbol` не предназначен для `<img>`.
|
|
||||||
|
|
||||||
Имена с пробелами и небезопасными символами получают hash ID `icon-<16 hex>`. Поэтому не предполагай, что basename всегда равен fragment; проверь generated SVG или preview.
|
|
||||||
|
|
||||||
## Preview
|
|
||||||
|
|
||||||
При `preview: true` после всех SVG создаётся `output/preview.html`. Он содержит данные и inline-копии generated sprites. При диагностике runtime и наличии браузерных инструментов его можно открыть для проверки числа иконок, `viewBox` и `--icon-color-N`.
|
|
||||||
|
|
||||||
При `preview: false` новый preview не создаётся. Генератор не является очистителем произвольных файлов output: если старый `preview.html` больше не нужен, удаляй его только после подтверждения, что это прежний generated artifact.
|
|
||||||
|
|
||||||
## Проверка
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run sprites
|
|
||||||
npm run typecheck
|
|
||||||
```
|
|
||||||
|
|
||||||
Генерация и typecheck проекта — быстрые обязательные проверки. Проверь для каждой entry:
|
|
||||||
|
|
||||||
- существует `public/sprites/<name>.sprite.svg`;
|
|
||||||
- в логе совпадают format и число иконок;
|
|
||||||
- ожидаемые `<symbol id="...">` либо вложенные `<svg id="...">` присутствуют;
|
|
||||||
- `preview.html` создан только при включённом preview;
|
|
||||||
- SVG со сложными `defs` проверены по [complex-svg.md](complex-svg.md).
|
|
||||||
|
|
||||||
Production build и браузер/Network запускай дополнительно только при изменении output/public pipeline или диагностике runtime. Тогда проверь URL реального приложения с учётом public base path и, если доступны визуальные инструменты, содержимое `preview.html`; не утверждай визуальный или a11y результат без такой проверки.
|
|
||||||
|
|
||||||
## Типовые ошибки
|
|
||||||
|
|
||||||
- `Config file not found`: CLI path не является каталогом с `svg-sprites.config.ts`.
|
|
||||||
- `Config file must have a default export`: экспортируй config через `defineLegacyConfig(...)`.
|
|
||||||
- Deprecated `mode`: поле `sprites[].mode` переименовано в `format`.
|
|
||||||
- `sprites must be a non-empty array`: legacy config не допускает пустую конфигурацию.
|
|
||||||
- `Input directory does not exist` или `SVG file does not exist`: помни, что paths считаются от каталога config при загрузке CLI.
|
|
||||||
- Вложенные SVG не найдены: directory scan не рекурсивен.
|
|
||||||
- Preview template not found при запуске из исходников пакета: собери package preview template; в опубликованном пакете он входит в distribution.
|
|
||||||
- Цвет не меняется в `<img>`: это изолированный SVG document; используй `<svg><use>` либо заранее заданные цвета.
|
|
||||||
- Старые output-файлы остались после удаления entry: legacy generator записывает текущие результаты, но не владеет очисткой всего output.
|
|
||||||
|
|
||||||
Программные варианты запуска и различия path resolution описаны в [programmatic-api.md](programmatic-api.md).
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
# Миграция с legacy API 0.1.x на latest: операционный reference
|
|
||||||
|
|
||||||
## Когда открывать
|
|
||||||
|
|
||||||
Открывай этот документ только при установленной или ранее использовавшейся версии `0.1.x`, старых вызовах `svg-sprites` без `--mode`, `defineConfig`, `generate`, `loadConfig`, поле `sprites[].mode`, `publicPath` или общем компоненте `<SvgSprite>`. Не выполняй миграцию как побочный рефакторинг.
|
|
||||||
|
|
||||||
## Инвентаризация до правок
|
|
||||||
|
|
||||||
Сначала зафиксируй текущий контракт проекта:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm ls @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Перед обновлением config и scripts установи актуальный пакет как development dependency:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Найди и прочитай:
|
|
||||||
|
|
||||||
- `svg-sprites.config.ts` и `svg-sprite.config.ts`;
|
|
||||||
- scripts, вызывающие `svg-sprites`;
|
|
||||||
- импорты `defineConfig`, `generate`, `loadConfig`, `SvgSprite`;
|
|
||||||
- ссылки на `publicPath`, `.sprite.svg`, старый generated-компонент и preview;
|
|
||||||
- правила `.gitignore`, SVG loaders и CI generation steps.
|
|
||||||
|
|
||||||
До изменений реши один из двух путей. Не смешивай их в одном CLI-вызове.
|
|
||||||
|
|
||||||
## Путь A: сохранить централизованный legacy pipeline
|
|
||||||
|
|
||||||
Выбирай его, если приложение зависит от общего `public/sprites`, `symbol`, статических URL или `preview.html`.
|
|
||||||
|
|
||||||
Маппинг API:
|
|
||||||
|
|
||||||
| Legacy API 0.1.x | Latest API |
|
|
||||||
|---|---|
|
|
||||||
| `defineConfig` | `defineLegacyConfig` |
|
|
||||||
| `sprites[].mode` | `sprites[].format` |
|
|
||||||
| `generate` | `generateLegacy` |
|
|
||||||
| `loadConfig` | `loadLegacyConfig` |
|
|
||||||
| CLI без mode | `svg-sprites --mode legacy <config-dir>` в package script |
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineLegacyConfig({
|
|
||||||
output: 'public/sprites',
|
|
||||||
preview: true,
|
|
||||||
sprites: [
|
|
||||||
{
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'symbol',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprites": "svg-sprites --mode legacy ."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Запусти его командой `npm run sprites`.
|
|
||||||
|
|
||||||
`publicPath` и генерация старого общего React-компонента удалены. Если приложение использовало этот компонент, legacy сохранит SVG asset, но React wrapper придётся заменить отдельно. Полный legacy workflow находится в [legacy.md](legacy.md).
|
|
||||||
|
|
||||||
## Путь B: перейти на локальные React/Next modules
|
|
||||||
|
|
||||||
Выбирай его, если нужны типизированные компоненты, hashed assets сборщика, Server Components или разбиение большого набора.
|
|
||||||
|
|
||||||
Для каждого нужного спрайта создай каталог проекта с локальным `svg-sprite.config.ts` и, при использовании папки, `icons/`. Каталог не обязан быть module/feature-каталогом; каждый config описывает один из потенциально многих спрайтов:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
|
||||||
name: 'global',
|
|
||||||
inputFolder: './icons',
|
|
||||||
inputFiles: ['../../../shared/icons/check.svg'],
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Для Next.js используй `defineNextSpriteConfig(...)`. Затем выбери ровно один mode:
|
|
||||||
|
|
||||||
| Среда | Mode |
|
|
||||||
|---|---|
|
|
||||||
| React + Vite | `react@vite` |
|
|
||||||
| React + Webpack 5 | `react@webpack` |
|
|
||||||
| Next App + Turbopack | `next@app/turbopack` |
|
|
||||||
| Next App + Webpack 5 | `next@app/webpack` |
|
|
||||||
| Next Pages + Turbopack | `next@pages/turbopack` |
|
|
||||||
| Next Pages + Webpack 5 | `next@pages/webpack` |
|
|
||||||
|
|
||||||
Пример:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"scripts": {
|
|
||||||
"sprite:global": "svg-sprites --mode react@vite src/ui/global/svg-sprite",
|
|
||||||
"sprites": "npm run sprite:global"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Запусти его командой `npm run sprite:global`.
|
|
||||||
|
|
||||||
Замени старый generic component:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// Было
|
|
||||||
<SvgSprite icon="check" />
|
|
||||||
|
|
||||||
// Стало при name: 'global'
|
|
||||||
<GlobalIcon icon="check" />
|
|
||||||
```
|
|
||||||
|
|
||||||
Новый модуль сам создаёт локальный `.gitignore`, `index.ts`, `manifest.ts` и `generated/`. SVG публикует bundler; не сохраняй старый `publicPath` и не копируй sprite в `public`.
|
|
||||||
|
|
||||||
Выбери детальную процедуру: [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md) или [next-pages.md](next-pages.md).
|
|
||||||
|
|
||||||
## Изменения программного API
|
|
||||||
|
|
||||||
Пакет теперь только ESM:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { compileSpriteContent, generateLegacy } from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
Не используй `require()`. `compileSpriteContent(...)` теперь возвращает `Promise<Uint8Array>`, а не Node-specific `Buffer` declaration:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const bytes = await compileSpriteContent(folder)
|
|
||||||
await fs.promises.writeFile('sprite.svg', bytes)
|
|
||||||
```
|
|
||||||
|
|
||||||
Если старый код вызывал `generate`, замени его на `generateLegacy`; для local modules используй `generateReactSprite` или `generateNextSprite`. Точные сигнатуры см. в [programmatic-api.md](programmatic-api.md).
|
|
||||||
|
|
||||||
## Безопасный порядок миграции
|
|
||||||
|
|
||||||
1. Зафиксируй список текущих icon names, formats, public URLs и цветовых ожиданий.
|
|
||||||
2. При миграции импортов обнови dependency до latest и config API, но не удаляй старые artifacts до успешной новой генерации.
|
|
||||||
3. Добавь явный mode и каталог во все local/CI scripts.
|
|
||||||
4. Сгенерируй новый output.
|
|
||||||
5. Замени imports и JSX usages; проверь TypeScript union icon names.
|
|
||||||
6. Если менялись target/pipeline или диагностируется runtime, проверь asset URLs и SSR/SSG; визуальный результат оценивай только доступными для этого инструментами.
|
|
||||||
7. Только после этого удали подтверждённые старые generated-файлы и устаревшие ignore/loader rules.
|
|
||||||
|
|
||||||
Не удаляй целиком каталог, в котором могут находиться исходные SVG или пользовательские файлы. Актуальный writer отказывается перезаписывать файлы без generated marker; не обходи эту защиту.
|
|
||||||
|
|
||||||
## Проверка после миграции
|
|
||||||
|
|
||||||
Минимум для npm-проекта:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run sprites
|
|
||||||
npm run typecheck
|
|
||||||
```
|
|
||||||
|
|
||||||
Используй реальные имена scripts проекта. Генерация и typecheck — быстрые обязательные проверки. Production build, браузер и Network добавляй, только если миграция меняет target/pipeline или диагностируется runtime. Проверь:
|
|
||||||
|
|
||||||
- ни один script не вызывает CLI без `--mode` и path;
|
|
||||||
- config helper и CLI mode относятся к одному pipeline;
|
|
||||||
- local manifest содержит ожидаемый target, а legacy output содержит ожидаемый format;
|
|
||||||
- старые `publicPath`, `sprites[].mode` и imports удалённого API отсутствуют;
|
|
||||||
- generated-файлы создаются до typecheck/build в чистом checkout;
|
|
||||||
- каждый старый icon name доступен либо намеренно переименован;
|
|
||||||
- цвета и сложные SVG исследованы по [complex-svg.md](complex-svg.md), без утверждений о визуальной или a11y корректности при отсутствии инструментов;
|
|
||||||
- `SpriteViewer` заменил отдельный preview только для React/Next; legacy по-прежнему может использовать `preview.html`.
|
|
||||||
|
|
||||||
## Типовые ошибки
|
|
||||||
|
|
||||||
- `Missing required argument: --mode`: старый script не обновлён.
|
|
||||||
- `React mode requires a target` или `Next.js mode requires a router and bundler`: указан сокращённый mode вместо полного ключа.
|
|
||||||
- Deprecated `mode`: в legacy entry осталось `sprites[].mode`.
|
|
||||||
- `icons was renamed to inputFolder`: старое поле перенесено в local React/Next config без переименования.
|
|
||||||
- `require() of ES Module`: build script не переведён на ESM/import.
|
|
||||||
- Иконки исчезли: local `inputFolder` сканируется нерекурсивно либо shared files не добавлены через `inputFiles`.
|
|
||||||
- Runtime ищет старый `/sprites/...`: JSX/CSS usage не переведён на generated component или новый asset URL.
|
|
||||||
- Один sprite генерируется разными targets: CI/local scripts не согласованы; оставь один target, соответствующий реальному bundler.
|
|
||||||
@@ -30,9 +30,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@app/turbopack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -41,7 +42,7 @@ export default defineNextSpriteConfig({
|
|||||||
```
|
```
|
||||||
|
|
||||||
- Каталог выбирает проект конкретного спрайта и не обязан быть module/feature-каталогом. Каждый config описывает один из потенциально многих спрайтов приложения.
|
- Каталог выбирает проект конкретного спрайта и не обязан быть module/feature-каталогом. Каждый config описывает один из потенциально многих спрайтов приложения.
|
||||||
- Конфиг называется в единственном числе: `svg-sprite.config.ts`.
|
- `svg-sprite.config.ts` — рекомендуемое имя; CLI принимает явно переданный `.ts`, `.js` или `.json` файл с любым именем.
|
||||||
- Пути считаются от его каталога; `inputFolder` сканируется нерекурсивно.
|
- Пути считаются от его каталога; `inputFolder` сканируется нерекурсивно.
|
||||||
- Локальная папка и `inputFiles` объединяются. Одинаковые basename разных файлов запрещены.
|
- Локальная папка и `inputFiles` объединяются. Одинаковые basename разных файлов запрещены.
|
||||||
- Если имя не задано, оно выводится из каталога: для папки `svg-sprite` берётся имя родительской папки. Явное `name` надёжнее при перемещениях.
|
- Если имя не задано, оно выводится из каталога: для папки `svg-sprite` берётся имя родительской папки. Явное `name` надёжнее при перемещениях.
|
||||||
@@ -56,7 +57,7 @@ export default defineNextSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -84,7 +85,7 @@ export default function Page() {
|
|||||||
|
|
||||||
`width` и `height` в JSX необязательны: размер можно задать CSS-классом или через `wrapped`. Не добавляй Client Component boundary только ради иконки. Generated module формирует asset URL через статический `new URL('./sprite.svg', import.meta.url).href`; один механизм используется при SSR и в браузере.
|
`width` и `height` в JSX необязательны: размер можно задать CSS-классом или через `wrapped`. Не добавляй Client Component boundary только ради иконки. Generated module формирует asset URL через статический `new URL('./sprite.svg', import.meta.url).href`; один механизм используется при SSR и в браузере.
|
||||||
|
|
||||||
Не импортируй из `generated/` и не перемещай SVG в `public`. Управляемые файлы (`generated/`, `index.ts`, `manifest.ts`, `.gitignore`) перегенерируются.
|
Не перемещай SVG в `public`. Генератор перезаписывает `.svg-sprite` и `.gitignore`; корневой `index.ts` принадлежит приложению и может содержать `export * from './.svg-sprite'`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
@@ -124,7 +125,7 @@ npm run build
|
|||||||
|
|
||||||
После обязательных генерации и typecheck проверь:
|
После обязательных генерации и typecheck проверь:
|
||||||
|
|
||||||
- `manifest.ts` содержит точный target `next@app/turbopack` либо `next@app/webpack`;
|
- `.svg-sprite/svg-sprite.manifest.js` содержит точный target `next@app/turbopack` либо `next@app/webpack`;
|
||||||
- server page компилируется без добавления `'use client'`;
|
- server page компилируется без добавления `'use client'`;
|
||||||
|
|
||||||
При условной production/runtime-проверке проверь также:
|
При условной production/runtime-проверке проверь также:
|
||||||
@@ -140,7 +141,7 @@ npm run build
|
|||||||
- Сборка проходит на одном bundler, а runtime asset ломается на другом: перегенерируй тем target, которым реально выполняется build.
|
- Сборка проходит на одном bundler, а runtime asset ломается на другом: перегенерируй тем target, которым реально выполняется build.
|
||||||
- Выбран Webpack, но build ушёл в Turbopack: используй Webpack-команду проекта и `next@app/webpack`.
|
- Выбран Webpack, но build ушёл в Turbopack: используй Webpack-команду проекта и `next@app/webpack`.
|
||||||
- Viewer вызывает ошибку Server Component: файл с Viewer должен иметь `'use client'`; generated icon component этого не требует.
|
- Viewer вызывает ошибку Server Component: файл с Viewer должен иметь `'use client'`; generated icon component этого не требует.
|
||||||
- `React config file not found`: команда получила путь к `app/`, `icons/` или конфигу вместо каталога спрайта.
|
- Config не найден: передай полный путь к существующему `.ts`, `.js` или `.json` config-файлу.
|
||||||
- Две CI jobs генерируют разные target в одном checkout: раздели каталоги или обеспечь один согласованный target на job.
|
- Две CI jobs генерируют разные target в одном checkout: раздели каталоги или обеспечь один согласованный target на job.
|
||||||
- Asset не найден под `basePath`/CDN: проверяй Next asset handling и deployment config, не подменяй generated URL вручную.
|
- Asset не найден под `basePath`/CDN: проверяй Next asset handling и deployment config, не подменяй generated URL вручную.
|
||||||
- Ошибка package subpath types: используй TypeScript 5+ и `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
- Ошибка package subpath types: используй TypeScript 5+ и `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'next@pages/webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -53,7 +54,7 @@ export default defineNextSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -79,7 +80,7 @@ export function getServerSideProps() {
|
|||||||
|
|
||||||
`width` и `height` в JSX необязательны: размер можно задать CSS-классом или через `wrapped`. Компонент работает при SSR, SSG и client navigation. Он использует `new URL('./sprite.svg', import.meta.url).href`, чтобы Next выпустил внешний hashed asset. Не копируй generated SVG в `public` и не конструируй URL вручную.
|
`width` и `height` в JSX необязательны: размер можно задать CSS-классом или через `wrapped`. Компонент работает при SSR, SSG и client navigation. Он использует `new URL('./sprite.svg', import.meta.url).href`, чтобы Next выпустил внешний hashed asset. Не копируй generated SVG в `public` и не конструируй URL вручную.
|
||||||
|
|
||||||
Импортируй компонент и типы только из локального `svg-sprite/index.ts`. Не редактируй `generated/`, `index.ts`, `manifest.ts` и созданный `.gitignore`.
|
Импортируй компонент и типы из локального пользовательского `svg-sprite/index.ts`, который переэкспортирует `.svg-sprite`. Не редактируй `.svg-sprite` и созданный `.gitignore`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ npm run build
|
|||||||
|
|
||||||
После обязательных генерации и typecheck проверь:
|
После обязательных генерации и typecheck проверь:
|
||||||
|
|
||||||
- `manifest.ts` содержит `next@pages/turbopack` либо `next@pages/webpack`;
|
- `.svg-sprite/svg-sprite.manifest.js` содержит `next@pages/turbopack` либо `next@pages/webpack`;
|
||||||
- `getServerSideProps`/`getStaticProps` не импортируют package React Viewer entry.
|
- `getServerSideProps`/`getStaticProps` не импортируют package React Viewer entry.
|
||||||
|
|
||||||
После условного production build и только при наличии браузерных инструментов проверь SSR route и переход на него:
|
После условного production build и только при наличии браузерных инструментов проверь SSR route и переход на него:
|
||||||
|
|||||||
@@ -1,244 +1,41 @@
|
|||||||
# Программный API: операционный reference
|
# Программный API: операционный reference
|
||||||
|
|
||||||
## Обязательная установка
|
Используй `generateSprite(source, overrides?)` как основной Node.js API.
|
||||||
|
|
||||||
```bash
|
## Из config-файла
|
||||||
npm install --save-dev @gromlab/svg-sprites
|
|
||||||
```
|
|
||||||
|
|
||||||
Программные imports требуют локальной development dependency, установленной выше. Этот reference описывает API установленной версии пакета.
|
|
||||||
|
|
||||||
## Когда открывать
|
|
||||||
|
|
||||||
Открывай этот документ, если генерация запускается из ESM build script, monorepo orchestration, собственного CLI или теста, а не напрямую package script. Для обычной интеграции предпочитай CLI references: [react-vite.md](react-vite.md), [react-webpack.md](react-webpack.md), [next-app.md](next-app.md), [next-pages.md](next-pages.md) или [legacy.md](legacy.md).
|
|
||||||
|
|
||||||
## Runtime и TypeScript
|
|
||||||
|
|
||||||
Основная точка входа только ESM и не импортирует React:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
import { generateSprite } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
|
await generateSprite('src/ui/icons/svg-sprite.config.ts')
|
||||||
```
|
```
|
||||||
|
|
||||||
Требуется Node.js 18+. Не используй `require()`. Для package subpath `@gromlab/svg-sprites/react` нужен TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
`source` должен указывать на конкретный `.ts`, `.js` или `.json` файл. Имя файла произвольное; генератор не выполняет discovery. Корнем sprite-модуля и базой относительных путей становится каталог этого файла.
|
||||||
|
|
||||||
## React module
|
## Без config-файла
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
await generateSprite('src/ui/icons', {
|
||||||
|
mode: 'react@vite',
|
||||||
const result = await generateReactSprite(
|
name: 'app',
|
||||||
'src/ui/file-manager/svg-sprite',
|
inputFolder: './icons',
|
||||||
'vite',
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Сигнатура target:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
type ReactAssetTarget = 'vite' | 'webpack'
|
|
||||||
```
|
|
||||||
|
|
||||||
`root` разрешается относительно текущего `process.cwd()`. Это выбранный каталог конкретного спрайта, а не обязательный module/feature-каталог. Внутри него функция загружает только `svg-sprite.config.ts`, объединяет `inputFolder` и `inputFiles`, компилирует `stack` и безопасно обновляет managed-файлы. Каждый такой config описывает один из потенциально многих спрайтов.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
type ReactSpriteGenerationResult = {
|
|
||||||
name: string
|
|
||||||
rootDir: string
|
|
||||||
generatedDir: string
|
|
||||||
spritePath: string
|
|
||||||
manifestPath: string
|
|
||||||
iconCount: number
|
|
||||||
target: 'vite' | 'webpack'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Передавай target явно. Значение вне union синхронно вызывает `Unsupported React asset target`.
|
|
||||||
|
|
||||||
## Next.js module
|
|
||||||
|
|
||||||
```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'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Результат содержит поля React result, target `next@<router>/<bundler>`, а также `router` и `bundler`. Next generation всегда использует `stack` и включает root `viewBox`. Выбранные options должны совпадать с фактической Next build command.
|
|
||||||
|
|
||||||
## Config helpers и загрузчики
|
|
||||||
|
|
||||||
Helpers только возвращают объект и дают autocomplete; они не загружают файлы и не запускают валидацию:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import {
|
|
||||||
defineLegacyConfig,
|
|
||||||
defineNextSpriteConfig,
|
|
||||||
defineReactSpriteConfig,
|
|
||||||
loadLegacyConfig,
|
|
||||||
loadReactSpriteConfig,
|
|
||||||
} from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const reactConfig = await loadReactSpriteConfig(
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
)
|
|
||||||
|
|
||||||
const legacyConfig = await loadLegacyConfig('.')
|
|
||||||
```
|
|
||||||
|
|
||||||
`loadReactSpriteConfig(root)` разрешает `inputFolder`/`inputFiles` от `root` и возвращает нормализованный config. Несмотря на название, тот же loader используется Next mode.
|
|
||||||
|
|
||||||
`loadLegacyConfig(cwd)` ищет `cwd/svg-sprites.config.ts`, валидирует его и превращает `output` и `sprites[].input` в absolute paths относительно `cwd`.
|
|
||||||
|
|
||||||
## Legacy generation
|
|
||||||
|
|
||||||
Прямой вызов:
|
|
||||||
|
|
||||||
```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
|
Каталог включает config-less режим. После объединения настроек `mode` обязателен.
|
||||||
type SpriteResult = {
|
|
||||||
name: string
|
|
||||||
format: 'symbol' | 'stack'
|
|
||||||
spritePath: string
|
|
||||||
iconCount: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Важный path nuance: `generateLegacy(config)` не знает местоположение config-файла. Относительные `output` и `input` разрешаются от текущего `process.cwd()`. Если semantics должны совпасть с CLI для config в другом каталоге, сначала вызови loader:
|
## Overrides
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const config = await loadLegacyConfig('config/sprites')
|
await generateSprite('src/ui/icons/custom.json', {
|
||||||
const results = await generateLegacy(config)
|
mode: 'react@webpack',
|
||||||
```
|
inputFiles: ['../../shared/search.svg'],
|
||||||
|
transform: { addTransition: false },
|
||||||
## Низкоуровневая компиляция
|
|
||||||
|
|
||||||
Основные exports:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import {
|
|
||||||
compileSprite,
|
|
||||||
compileSpriteContent,
|
|
||||||
createShapeTransform,
|
|
||||||
generatePreview,
|
|
||||||
resolveSpriteEntry,
|
|
||||||
resolveSprites,
|
|
||||||
} from '@gromlab/svg-sprites'
|
|
||||||
```
|
|
||||||
|
|
||||||
Минимальный in-memory пример:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { compileSpriteContent, resolveSpriteEntry } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const folder = resolveSpriteEntry({
|
|
||||||
name: 'icons',
|
|
||||||
input: 'src/assets/icons',
|
|
||||||
format: 'stack',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const bytes = await compileSpriteContent(
|
|
||||||
folder,
|
|
||||||
{
|
|
||||||
removeSize: true,
|
|
||||||
replaceColors: true,
|
|
||||||
addTransition: true,
|
|
||||||
},
|
|
||||||
{ rootViewBox: false },
|
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`compileSpriteContent` возвращает `Promise<Uint8Array>` и не пишет на диск. `compileSprite(folder, outputDir, transform?, options?)` создаёт output directory и записывает `<folder.name>.sprite.svg`.
|
Порядок: `defaults → config → API overrides`. `transform` объединяется по отдельным полям; переданный `inputFiles` заменяет массив из config.
|
||||||
|
|
||||||
`CompileSpriteOptions.rootViewBox` по умолчанию `false`; стандартный Next preset передаёт `true`, React и legacy оставляют `false`. Не меняй эту опцию в попытке заменить target: она не определяет способ публикации asset.
|
Специализированные `generateReactSprite` и `generateNextSprite` оставлены как совместимые обёртки, но для нового кода предпочитай `generateSprite`.
|
||||||
|
|
||||||
`resolveSpriteEntry` и `resolveSprites` разрешают source paths относительно `process.cwd()`, проверяют existence и читают directory только на первом уровне. Они не применяют semantics локального `inputFolder + inputFiles`; для стандартных React/Next modules используй high-level generators.
|
Для загрузки и собственной оркестрации доступны `loadSpriteConfig`, `validateSpriteConfig`, `resolveSpriteConfig`, `compileSpriteContent` и `createShapeTransform`.
|
||||||
|
|
||||||
`createShapeTransform(options)` возвращает callback transform для `svg-sprite`. Это integration primitive, а не функция `string -> string`.
|
|
||||||
|
|
||||||
`generatePreview(results, outputDir)` ожидает, что `results[].spritePath` уже существует, и пишет `preview.html` на основе package template. Не вызывай его до компиляции.
|
|
||||||
|
|
||||||
## React debug runtime
|
|
||||||
|
|
||||||
Viewer находится в отдельной client entry:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|
||||||
import type {
|
|
||||||
SpriteManifest,
|
|
||||||
SpriteManifestLoader,
|
|
||||||
SpriteManifestModule,
|
|
||||||
SpriteViewerColorTheme,
|
|
||||||
SpriteViewerProps,
|
|
||||||
SpriteViewerSources,
|
|
||||||
} from '@gromlab/svg-sprites/react'
|
|
||||||
```
|
|
||||||
|
|
||||||
`SpriteViewerSources` принимает массив manifest/loader или record, например результат Vite `import.meta.glob`. Loader может вернуть manifest напрямую либо module с `default`/`spriteManifest`. Невалидный module завершится ошибкой `The loaded module does not export a valid SVG sprite manifest.`
|
|
||||||
|
|
||||||
Package React entry содержит `'use client'`; не импортируй его из server-only build scripts и production icon modules. Generated production component находится в выбранном каталоге спрайта.
|
|
||||||
|
|
||||||
## Оркестрация нескольких модулей
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
|
||||||
|
|
||||||
const roots = [
|
|
||||||
'src/ui/global/svg-sprite',
|
|
||||||
'src/ui/file-manager/svg-sprite',
|
|
||||||
]
|
|
||||||
|
|
||||||
const results = await Promise.all(
|
|
||||||
roots.map((root) => generateReactSprite(root, 'vite')),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (results.some((result) => result.iconCount === 0)) {
|
|
||||||
throw new Error('Пустой sprite module')
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Не запускай разные targets параллельно для одного root: оба вызова владеют одинаковыми generated paths.
|
|
||||||
|
|
||||||
## Проверка и обработка ошибок
|
|
||||||
|
|
||||||
Запусти программную генерацию и typecheck проекта — это быстрые обязательные проверки. После вызова проверь `result.target`, `iconCount`, existence `spritePath`/`manifestPath`. Реальную bundler build и browser/Network-проверку добавляй только при изменении target/pipeline или диагностике runtime; не утверждай визуальный или a11y результат без доступных инструментов.
|
|
||||||
|
|
||||||
Типовые причины failure:
|
|
||||||
|
|
||||||
- unsupported target/router/bundler передан как unchecked string;
|
|
||||||
- `process.cwd()` отличается в monorepo runner, поэтому relative root указывает не туда;
|
|
||||||
- config не имеет default export;
|
|
||||||
- явно заданная `inputFolder` отсутствует;
|
|
||||||
- два source-файла дают одинаковый fragment ID;
|
|
||||||
- custom orchestration пытается перезаписать пользовательский файл в managed path;
|
|
||||||
- `generatePreview` не находит template при запуске из несобранных исходников package;
|
|
||||||
- сложный SVG требует отключения отдельных transforms по [complex-svg.md](complex-svg.md).
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
1. Проверь `package.json`: должны быть React, Vite и фактические команды `dev`, `build`, `typecheck`.
|
1. Проверь `package.json`: должны быть React, Vite и фактические команды `dev`, `build`, `typecheck`.
|
||||||
2. Найди существующие `svg-sprite.config.ts` и scripts с `svg-sprites`. Не создавай второй каталог для уже существующего спрайта.
|
2. Найди существующие `svg-sprite.config.ts` и scripts с `svg-sprites`. Не создавай второй каталог для уже существующего спрайта.
|
||||||
3. Выбери целевой каталог для конкретного спрайта. Это не обязан быть каталог module или feature: генератор принимает каталог с config, а не путь к самому config или `icons/`.
|
3. Выбери целевой каталог для конкретного спрайта. Это не обязан быть каталог module или feature: генератор принимает каталог с config, а не путь к самому config или `icons/`.
|
||||||
4. Не редактируй вручную `generated/`, `index.ts`, `manifest.ts` и локальный `.gitignore`: ими владеет генератор.
|
4. Не редактируй вручную `.svg-sprite` и локальный `.gitignore`: ими владеет генератор. Корневой `index.ts` принадлежит приложению.
|
||||||
|
|
||||||
Минимальная структура:
|
Минимальная структура:
|
||||||
|
|
||||||
@@ -32,9 +32,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@vite',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -58,7 +59,7 @@ export default defineReactSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -95,7 +96,7 @@ export const availableIcons = fileManagerIconNames
|
|||||||
<FileManagerIcon icon="folder" wrapped className="iconBox" />
|
<FileManagerIcon icon="folder" wrapped className="iconBox" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Не делай deep import из `generated/`: структура generated-файлов не является точкой интеграции.
|
Для обычного импорта используй пользовательский barrel с `export * from './.svg-sprite'`; остальные файлы скрытого каталога считаются внутренними.
|
||||||
|
|
||||||
## Нюанс target
|
## Нюанс target
|
||||||
|
|
||||||
@@ -110,14 +111,14 @@ Query `?no-inline` обязателен: он не даёт Vite преврат
|
|||||||
Для низкоуровневого `<use>` применяй тот же механизм:
|
Для низкоуровневого `<use>` применяй тот же механизм:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
import spriteUrl from './svg-sprite/.svg-sprite/sprite.svg?no-inline'
|
||||||
|
|
||||||
<svg className="icon">
|
<svg className="icon">
|
||||||
<use href={`${spriteUrl}#check`} />
|
<use href={`${spriteUrl}#check`} />
|
||||||
</svg>
|
</svg>
|
||||||
```
|
```
|
||||||
|
|
||||||
Ручной fragment `#check` безопасен только для имён вида `^[a-zA-Z][a-zA-Z0-9_-]*$`. Для пробелов и других символов generated-компонент использует стабильный hash ID; точный ID находится в `manifest.ts`.
|
Ручной fragment `#check` безопасен только для имён вида `^[a-zA-Z][a-zA-Z0-9_-]*$`. Для пробелов и других символов generated-компонент использует стабильный hash ID; точный ID находится в `.svg-sprite/svg-sprite.manifest.js`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
|||||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||||
|
|
||||||
const sources = import.meta.glob<SpriteManifestModule>(
|
const sources = import.meta.glob<SpriteManifestModule>(
|
||||||
'/src/**/svg-sprite/manifest.ts',
|
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
export function IconsDebugPage() {
|
export function IconsDebugPage() {
|
||||||
@@ -136,7 +137,7 @@ export function IconsDebugPage() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Аргумент `import.meta.glob` должен оставаться строковым литералом. Генерация обязана завершиться до старта Vite, иначе новые `manifest.ts` не попадут в glob.
|
Аргумент `import.meta.glob` должен оставаться строковым литералом. Генерация обязана завершиться до старта Vite, иначе новые manifests не попадут в glob.
|
||||||
|
|
||||||
## Проверка результата
|
## Проверка результата
|
||||||
|
|
||||||
@@ -147,18 +148,18 @@ npm run typecheck
|
|||||||
|
|
||||||
Это быстрые обязательные проверки. Проверь generated-файлы статически:
|
Это быстрые обязательные проверки. Проверь generated-файлы статически:
|
||||||
|
|
||||||
- публичный `index.ts` экспортирует компонент, props, style, union имени и runtime-массив;
|
- пользовательский `index.ts` переэкспортирует компонент, props, style, union имени и runtime-массив из `.svg-sprite`;
|
||||||
- `manifest.ts` содержит `target: "vite"`, `format: "stack"` и ожидаемое число иконок;
|
- `.svg-sprite/svg-sprite.manifest.js` содержит `target: "vite"`, `format: "stack"` и ожидаемое число иконок;
|
||||||
|
|
||||||
Если менялись target, asset pipeline или диагностируется runtime, дополнительно запусти production build. При наличии браузерных инструментов проверь Network: отдельный `.svg` asset вместо `data:image/svg+xml`, успешный URL и `<use href="...svg#...">`. Для сложных цветов, `defs` и размеров следуй [complex-svg.md](complex-svg.md), не утверждая визуальный или a11y результат без доступных инструментов.
|
Если менялись target, asset pipeline или диагностируется runtime, дополнительно запусти production build. При наличии браузерных инструментов проверь Network: отдельный `.svg` asset вместо `data:image/svg+xml`, успешный URL и `<use href="...svg#...">`. Для сложных цветов, `defs` и размеров следуй [complex-svg.md](complex-svg.md), не утверждая визуальный или a11y результат без доступных инструментов.
|
||||||
|
|
||||||
## Типовые ошибки
|
## Типовые ошибки
|
||||||
|
|
||||||
- `React config file not found`: в команду передан путь к `icons/` или к файлу; передай каталог, содержащий `svg-sprite.config.ts`.
|
- Config не найден: передай полный путь к существующему `.ts`, `.js` или `.json` config-файлу.
|
||||||
- `React mode requires a target`: использован `--mode react`; нужен ровно `react@vite`.
|
- `Sprite mode is required`: добавь `mode: 'react@vite'` в config либо передай `--mode react@vite`.
|
||||||
- Иконки нет в autocomplete: проверь case-sensitive окончание `.svg`, нерекурсивное расположение и повторно запусти генерацию до typecheck.
|
- Иконки нет в autocomplete: проверь case-sensitive окончание `.svg`, нерекурсивное расположение и повторно запусти генерацию до typecheck.
|
||||||
- `Refusing to overwrite a user file`: не удаляй marker и не обходи writer; перенеси пользовательский файл или выбери другой sprite-каталог.
|
- `Refusing to overwrite a user file`: не удаляй marker и не обходи writer; перенеси пользовательский файл или выбери другой sprite-каталог.
|
||||||
- Viewer пуст: проверь строковый glob, существование generated `manifest.ts` и порядок запуска `predev`.
|
- Viewer пуст: проверь строковый glob, существование `.svg-sprite/svg-sprite.manifest.js` и порядок запуска `predev`.
|
||||||
- SVG оказался inline: проверь, что модуль сгенерирован target `vite` и импорт сохранил `?no-inline`.
|
- SVG оказался inline: проверь, что модуль сгенерирован target `vite` и импорт сохранил `?no-inline`.
|
||||||
- TypeScript не разрешает package subpath: используй TypeScript 5+ и `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
- TypeScript не разрешает package subpath: используй TypeScript 5+ и `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ npm install --save-dev @gromlab/svg-sprites
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineSpriteConfig({
|
||||||
|
mode: 'react@webpack',
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'Иконки файлового менеджера',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
@@ -49,7 +50,7 @@ export default defineReactSpriteConfig({
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
"sprite:file-manager": "svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||||
"predev": "npm run sprite:file-manager",
|
"predev": "npm run sprite:file-manager",
|
||||||
"prebuild": "npm run sprite:file-manager",
|
"prebuild": "npm run sprite:file-manager",
|
||||||
"pretypecheck": "npm run sprite:file-manager"
|
"pretypecheck": "npm run sprite:file-manager"
|
||||||
@@ -74,7 +75,7 @@ export function OpenFolderButton() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`width` и `height` в JSX необязательны: размер можно задать CSS-классом или через `wrapped`. Публичный entry также экспортирует `FileManagerIconProps`, `FileManagerIconStyle`, `FileManagerIconName` и `fileManagerIconNames`. Не импортируй файлы напрямую из `generated/` и не редактируй `generated/`, `index.ts`, `manifest.ts` или созданный `.gitignore`.
|
`width` и `height` в JSX необязательны: размер можно задать CSS-классом или через `wrapped`. Пользовательский barrel также экспортирует `FileManagerIconProps`, `FileManagerIconStyle`, `FileManagerIconName` и `fileManagerIconNames`. Не редактируй `.svg-sprite` или созданный `.gitignore`.
|
||||||
|
|
||||||
## Нюанс Webpack target
|
## Нюанс Webpack target
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ Webpack 5 распознаёт его как Asset Module и заменяет н
|
|||||||
|
|
||||||
- не оборачивай путь в переменную и не меняй generated expression;
|
- не оборачивай путь в переменную и не меняй generated expression;
|
||||||
- убедись, что Babel/TypeScript не преобразует `import.meta.url` до Webpack;
|
- убедись, что Babel/TypeScript не преобразует `import.meta.url` до Webpack;
|
||||||
- не позволяй `@svgr/webpack`, `svg-inline-loader`, `raw-loader` или общему SVG rule перехватить `svg-sprite/generated/sprite.svg`;
|
- не позволяй `@svgr/webpack`, `svg-inline-loader`, `raw-loader` или общему SVG rule перехватить `svg-sprite/.svg-sprite/sprite.svg`;
|
||||||
- при custom rule либо исключи generated sprite из component/raw loader, либо добавь отдельное правило `type: 'asset/resource'`;
|
- при custom rule либо исключи generated sprite из component/raw loader, либо добавь отдельное правило `type: 'asset/resource'`;
|
||||||
- проверь `output.publicPath`, особенно при CDN, subpath deployment и dev-server.
|
- проверь `output.publicPath`, особенно при CDN, subpath deployment и dev-server.
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ Webpack 5 распознаёт его как Asset Module и заменяет н
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
test: /svg-sprite[\\/]generated[\\/]sprite\.svg$/,
|
test: /svg-sprite[\\/]\.svg-sprite[\\/]sprite\.svg$/,
|
||||||
type: 'asset/resource',
|
type: 'asset/resource',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -131,7 +132,7 @@ npm run typecheck
|
|||||||
|
|
||||||
Это быстрые обязательные проверки. После генерации проверь:
|
Это быстрые обязательные проверки. После генерации проверь:
|
||||||
|
|
||||||
- `manifest.ts` содержит `target: "webpack"` и `format: "stack"`;
|
- `.svg-sprite/svg-sprite.manifest.js` содержит `target: "webpack"` и `format: "stack"`;
|
||||||
- generated component содержит `new URL('./sprite.svg', import.meta.url).href`;
|
- generated component содержит `new URL('./sprite.svg', import.meta.url).href`;
|
||||||
|
|
||||||
Production build и браузер/Network нужны дополнительно, если менялись target, Webpack asset rules, `publicPath`/deployment pipeline или диагностируется runtime. Тогда проверь отдельный hashed SVG asset, HTTP(S)-URL `.svg#id`, content type, fragment ID и корректный CDN/subpath URL. Не утверждай визуальную или a11y корректность без доступных инструментов.
|
Production build и браузер/Network нужны дополнительно, если менялись target, Webpack asset rules, `publicPath`/deployment pipeline или диагностируется runtime. Тогда проверь отдельный hashed SVG asset, HTTP(S)-URL `.svg#id`, content type, fragment ID и корректный CDN/subpath URL. Не утверждай визуальную или a11y корректность без доступных инструментов.
|
||||||
@@ -145,7 +146,7 @@ Production build и браузер/Network нужны дополнительно
|
|||||||
- URL ведёт на неверный host/subpath: исправь `output.publicPath` и настройки runtime deployment, не generated-файл.
|
- URL ведёт на неверный host/subpath: исправь `output.publicPath` и настройки runtime deployment, не generated-файл.
|
||||||
- `import.meta` не поддержан: проверь, что сборка действительно Webpack 5 и промежуточный transpiler сохраняет выражение.
|
- `import.meta` не поддержан: проверь, что сборка действительно Webpack 5 и промежуточный transpiler сохраняет выражение.
|
||||||
- Viewer не загружает manifest: проверь literal path, chunk loading и наличие генерации до компиляции.
|
- Viewer не загружает manifest: проверь literal path, chunk loading и наличие генерации до компиляции.
|
||||||
- `Refusing to overwrite a user file`: каталог уже содержит пользовательский `index.ts`, `manifest.ts`, `.gitignore` или файл в `generated/`; перенеси его, не обходи защиту.
|
- `Refusing to overwrite a user file`: каталог уже содержит пользовательский `.gitignore` или файл в `.svg-sprite`; перенеси его, не обходи защиту.
|
||||||
- Иконка не меняет цвет: используй `color` для монохромной либо `--icon-color-N` через `<svg><use>`; CSS страницы не проникает внутрь `<img>`.
|
- Иконка не меняет цвет: используй `color` для монохромной либо `--icon-color-N` через `<svg><use>`; CSS страницы не проникает внутрь `<img>`.
|
||||||
|
|
||||||
Для custom build orchestration см. [programmatic-api.md](programmatic-api.md).
|
Для custom build orchestration см. [programmatic-api.md](programmatic-api.md).
|
||||||
|
|||||||
Reference in New Issue
Block a user