mirror of
https://github.com/gromlab-ru/svg-sprites.git
synced 2026-07-22 12:40:21 +03:00
Compare commits
11 Commits
chore/rele
...
fix/update
| Author | SHA1 | Date | |
|---|---|---|---|
| 00fa6cea28 | |||
|
|
b9451c8ff3 | ||
| 1b6a5cb90c | |||
|
|
cb40d4eb04 | ||
| 873704abd6 | |||
| 3f6b186a5b | |||
|
|
c7e6a27236 | ||
| b4869deb97 | |||
|
|
07d57e3838 | ||
| 1b5b446d8f | |||
|
|
b3a3a8347a |
55
FEATURES.md
Normal file
55
FEATURES.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Иконки без лишней цены для приложения
|
||||
|
||||
`@gromlab/svg-sprites` превращает SVG проекта в кешируемую, типизированную систему иконок для React и Next.js. В коде остаются простые компоненты, а приложение получает преимущества спрайтов без сложной инфраструктуры.
|
||||
|
||||
1. **AI-friendly из коробки**
|
||||
|
||||
`@gromlab/svg-sprites` сразу рассчитан на работу с AI-агентами. Подключите готовый skill и поручите агенту настройку, миграцию или диагностику без длинных инструкций и ручного изучения документации.
|
||||
|
||||
2. **Типизированный React-компонент с автокомплитом**
|
||||
|
||||
Каждый спрайт получает собственный готовый компонент. Prop `icon` формируется из реальных имён SVG, поэтому редактор показывает точный список доступных иконок, а TypeScript сразу обнаруживает опечатки. Не нужно вручную поддерживать компоненты, union-типы или реестр имён.
|
||||
|
||||
3. **Next.js App Router и SSR из коробки**
|
||||
|
||||
Generated-компоненты работают в Server Components, SSR и SSG без `'use client'`. Подключение иконки не переносит страницу на клиент и не требует provider или дополнительной гидратации.
|
||||
|
||||
4. **Множественные спрайты вместо одного глобального**
|
||||
|
||||
Проект не ограничен одним набором иконок. Создавайте независимые спрайты для общих элементов, отдельных страниц и крупных UI-модулей. Каждый набор получает собственный типизированный компонент и SVG asset, поэтому разделы приложения не несут иконки, которые им не нужны.
|
||||
|
||||
5. **Каждая иконка хранится в одном экземпляре**
|
||||
|
||||
Одна SVG-иконка может входить в любое количество спрайтов. Общие иконки не приходится копировать между страницами и модулями: они хранятся в одном месте и обновляются сразу для всех наборов.
|
||||
|
||||
6. **Браузерное кэширование**
|
||||
|
||||
Каждый спрайт выпускается отдельным версионированным SVG-файлом. Пока его набор иконок не меняется, браузер может использовать сохранённую копию независимо от обновлений JavaScript приложения.
|
||||
|
||||
7. **JavaScript без SVG-балласта**
|
||||
|
||||
Контуры иконок остаются во внешних SVG assets и не увеличивают chunks приложения. JavaScript отвечает за интерфейс и поведение, а графика загружается и кешируется отдельно.
|
||||
|
||||
8. **Трансформации SVG из коробки**
|
||||
|
||||
Во время генерации пакет автоматически подготавливает исходные SVG для интерфейса: удаляет фиксированные `width` и `height` с сохранением `viewBox`, преобразует `fill` и `stroke` в CSS-переменные и добавляет плавные transitions непосредственно в цветные элементы иконки. Каждую трансформацию можно настроить или отключить независимо.
|
||||
|
||||
9. **Каждый цвет под контролем CSS**
|
||||
|
||||
При генерации цвета `fill` и `stroke` автоматически преобразуются в CSS-переменные `--icon-color-N`. Монохромная иконка наследует `currentColor`, а в многоцветной каждый цвет можно менять отдельно. Темы, состояния и hover-эффекты создаются без редактирования SVG и дополнительных копий иконки.
|
||||
|
||||
10. **SpriteViewer: все спрайты на одной debug-странице**
|
||||
|
||||
`SpriteViewer` рендерит все спрайты проекта в одном месте и показывает, какие иконки вошли в каждый набор и как они выглядят. Для каждой иконки видны созданные CSS-переменные и их fallback-цвета. Значения можно менять прямо в Viewer и сразу наблюдать результат. Здесь же доступны готовые примеры подключения через React, `<svg><use>`, `<img>` и CSS.
|
||||
|
||||
11. **От нативного HTML до Next.js**
|
||||
|
||||
В основе остаётся обычный SVG-спрайт, который можно использовать даже без фреймворка и сборщика. Для React и Next.js пакет генерирует типизированные компоненты и поддерживает Vite, Webpack 5 и Turbopack. Список готовых интеграций будет расширяться новыми фреймворками.
|
||||
|
||||
12. **Чистый Git**
|
||||
|
||||
Generated-файлы автоматически исключаются из Git и не засоряют историю, pull requests и код проекта. В репозитории остаются только исходные SVG и конфигурация, а локально и в CI спрайты, компоненты и типы заново создаются через `prebuild`.
|
||||
|
||||
13. **В production только иконки**
|
||||
|
||||
`@gromlab/svg-sprites` выполняет всю работу на этапе генерации и остаётся в `devDependencies`. Compiler и CLI не попадают в клиентское приложение: после сборки остаются только локальный типизированный компонент и внешний SVG-файл.
|
||||
525
README.md
525
README.md
@@ -4,400 +4,261 @@
|
||||
|
||||
 
|
||||
|
||||
A CLI for generating SVG sprites and typed icon components for React and Next.js.
|
||||
`@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.
|
||||
|
||||
## AI Skills
|
||||
## An SVG sprite as simple as a regular SVG icon
|
||||
|
||||
- [🇬🇧 Download the English skill (latest)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites.zip)
|
||||
- [🇷🇺 Download the Russian skill (latest)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites-ru.zip)
|
||||
One typed React component is generated for the entire sprite. Choose an icon with the `icon` prop, and your editor will autocomplete every available name.
|
||||
|
||||
## Navigation
|
||||
|
||||
- [AI Skills](#ai-skills)
|
||||
- [Features](#features)
|
||||
- [Support matrix](#support-matrix)
|
||||
- [Requirements](#requirements)
|
||||
- [Quick start](#quick-start)
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
- [Next.js App Router](docs/en/next-app.md)
|
||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||
- [Configuration](#configuration)
|
||||
- [React](#react)
|
||||
- [Next.js](#nextjs)
|
||||
- [Multiple sprites](#multiple-sprites)
|
||||
- [TypeScript](#typescript)
|
||||
- [Sprite formats](#sprite-formats)
|
||||
- [Rendering methods](#rendering-methods)
|
||||
- [Transformations](#transformations)
|
||||
- [Icon color management](#icon-color-management)
|
||||
- [Caching](#caching)
|
||||
- [SpriteViewer](#spriteviewer)
|
||||
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||
- [Documentation](#documentation)
|
||||
|
||||
## Features
|
||||
|
||||
- **AI-agent friendly** - the repository includes a ready-to-use skill with up-to-date documentation for configuring, migrating, and troubleshooting `@gromlab/svg-sprites`.
|
||||
- **TypeScript-friendly** - typed React components, union types, and runtime lists of available icons.
|
||||
- **Clean generation** - generated files are automatically excluded from Git, the sprite does not need to be placed in `public` manually, and the generator updates only files it owns.
|
||||
- **Shared icons without copying** - SVGs from the local folder and `inputFiles` are merged into a single sprite; one file can be used in multiple sprites.
|
||||
- **Built-in interactive preview** - `<SpriteViewer>` is integrated as an application page and displays the provided React and Next.js sprites with search, color controls, and usage examples.
|
||||
- **Configurable SVG transformations** - remove `width` and `height` while preserving `viewBox`, replace source colors with CSS variables, and add transitions for `fill` and `stroke`.
|
||||
- **Separate cacheable SVG asset** - SVG path data does not end up in JavaScript chunks, and the bundler emits a file with a content hash.
|
||||
- **Multiple sprites** - independent React and Next.js modules with their own components, types, and SVG assets.
|
||||
- **Server-first Next.js** - generated components work in Server Components, SSR, and SSG without the `'use client'` directive.
|
||||
- **Formats for different use cases** - React and Next.js use `stack`; legacy mode also supports `symbol` for existing integrations.
|
||||
|
||||
## Support matrix
|
||||
|
||||
| Environment | API mode key | Status |
|
||||
|---|---|---|
|
||||
| React + Vite | `react@vite` | Ready |
|
||||
| React + Webpack 5 | `react@webpack` | Ready |
|
||||
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Ready |
|
||||
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Ready |
|
||||
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Ready |
|
||||
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Ready |
|
||||
| Vue | - | Coming soon |
|
||||
| Standalone | - | Coming soon |
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18 or newer;
|
||||
- the package is distributed as ESM only and is loaded via `import`;
|
||||
- React 18 or 19 is required only for generated components and the `@gromlab/svg-sprites/react` entry point;
|
||||
- for subpath export typings, use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||
|
||||
## Quick start
|
||||
|
||||
For a quick start, follow the guide for your stack:
|
||||
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
- [Next.js App Router](docs/en/next-app.md)
|
||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||
|
||||
## Configuration
|
||||
|
||||
### React
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: [
|
||||
'../../shared/icons/check.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
| Option | Type | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `name` | `string` | Folder name | Name of the sprite, component, and public types |
|
||||
| `description` | `string` | None | Description for types and the debug manifest |
|
||||
| `inputFolder` | `string` | `./icons` | Folder containing source SVGs, relative to the config |
|
||||
| `inputFiles` | `string[]` | `[]` | Additional SVG files, relative to the config |
|
||||
| `transform` | `TransformOptions` | All enabled | [Transformation settings](#transformations) for source SVGs |
|
||||
| `generatedNotice` | `boolean` | `true` | Full or short warning in generated files |
|
||||
The component accepts familiar SVG attributes: dimensions, `color`, `className`, `style`, `aria-*`, and event handlers. If you need an outer container, add `wrapped`.
|
||||
|
||||
`inputFolder` and `inputFiles` are merged into a single sprite, so one SVG file can be used in multiple sprites without copying. If the implicit `./icons` folder does not exist but `inputFiles` is populated, generation continues using only the list. An explicitly specified missing folder is an error. Duplicate paths are deduplicated, while different files with the same icon name are treated as an error.
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
`name` is stored in kebab-case and must start with a Latin letter. The React and Next.js presets produce the `stack` format.
|
||||
You do not have to work with the sprite directly in your application. Use it like a regular SVG icon while benefiting from a single component, autocomplete, and TypeScript validation for every name.
|
||||
|
||||
### Next.js
|
||||
## AI-friendly out of the box
|
||||
|
||||
Next.js uses the same `svg-sprite.config.ts` and set of options. For type checking, you can use a dedicated helper:
|
||||
`@gromlab/svg-sprites` is designed to work with AI agents from the start. Add the ready-made skill and ask an agent to configure, migrate, or troubleshoot the package without lengthy instructions or manual documentation research.
|
||||
|
||||
[🇬🇧 Download AI skill (English)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites.zip)
|
||||
|
||||
[🇷🇺 Download AI skill (Russian)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites-ru.zip)
|
||||
|
||||
## From SVG to component in four steps
|
||||
|
||||
The main example uses the Next.js App Router and Turbopack.
|
||||
|
||||
### 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
### 2. Specify the icons you need
|
||||
|
||||
SVG files can remain in your project's existing structure:
|
||||
|
||||
```text
|
||||
src/
|
||||
├── assets/icons/
|
||||
│ ├── search.svg
|
||||
│ └── settings.svg
|
||||
├── features/profile/
|
||||
│ └── user.svg
|
||||
└── ui/app-icons/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Create the sprite configuration:
|
||||
|
||||
```ts
|
||||
// src/ui/app-icons/svg-sprite.config.ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
name: 'app',
|
||||
inputFiles: [
|
||||
'../../assets/icons/search.svg',
|
||||
'../../assets/icons/settings.svg',
|
||||
'../../features/profile/user.svg',
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
The router and bundler are selected through the mode key, so switching between Turbopack and Webpack is always explicitly reflected in the generation command.
|
||||
### 3. Add generation
|
||||
|
||||
## Multiple sprites
|
||||
|
||||
An application can contain several independent sprites for different scopes:
|
||||
|
||||
**Problem:** one global sprite loads icons that the current screen does not need.
|
||||
|
||||
**Solution:** keep shared icons globally, and place icon sets for pages and large components in separate sprites that load alongside them.
|
||||
|
||||
```text
|
||||
global -> GlobalIcon -> shared application icons
|
||||
analytics-page -> AnalyticsPageIcon -> icons for a specific page
|
||||
file-manager -> FileManagerIcon -> icons for a large component
|
||||
```
|
||||
|
||||
- **Global sprite** contains a small set of shared icons used in different parts of the application: navigation, states, and basic actions.
|
||||
- **Page sprite** loads with a specific section and does not increase the shared sprite with icons that are not needed anywhere else.
|
||||
- **Large component sprite** encapsulates the icon set of a complex UI module, such as a file manager or editor.
|
||||
|
||||
Each group gets:
|
||||
|
||||
- its own SVG asset;
|
||||
- its own typed component;
|
||||
- a separate list of icon names;
|
||||
- a separate debug manifest;
|
||||
- an independent cache lifecycle.
|
||||
|
||||
|
||||
## TypeScript
|
||||
|
||||
The main feature of the TypeScript API is icon name autocomplete directly in the `icon` prop:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="folder" />
|
||||
// ^ the editor suggests every icon in the sprite
|
||||
```
|
||||
|
||||
SVG file names become valid `icon` values. A typo or unknown name immediately becomes a TypeScript error:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="unknown" /> // TypeScript error
|
||||
```
|
||||
|
||||
For programmatic access, the generated module exports a readonly array of all icons available in a specific sprite:
|
||||
|
||||
```ts
|
||||
import { fileManagerIconNames } from './svg-sprite'
|
||||
|
||||
// readonly ['check', 'folder', ...]
|
||||
```
|
||||
|
||||
You can use this list in custom catalogs, select components, tests, and other runtime scenarios. The `FileManagerIconName` union type is also derived from it.
|
||||
|
||||
File names containing spaces and other characters unsafe for SVG IDs remain part of the public TypeScript API. For the internal `<symbol id>`, the generator creates a stable hash ID.
|
||||
|
||||
```text
|
||||
folder open.svg -> icon="folder open" -> id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
For such names, use the generated component or the `id` from the debug manifest. The manual examples below using `#<name>` are suitable only for names that are already safe SVG IDs.
|
||||
|
||||
## Sprite formats
|
||||
|
||||
`stack` is the more modern format, so it is used by default. Icons can be rendered through `<svg><use>`, `<img>`, and CSS `background-image`.
|
||||
|
||||
`symbol` is retained for compatibility with existing integrations and supports rendering only through `<svg><use>`.
|
||||
|
||||
## Rendering methods
|
||||
|
||||
### React component - recommended
|
||||
|
||||
The generated component provides type safety and icon name autocomplete, and constructs the SVG asset URL itself.
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="check" width={24} height={24} />
|
||||
```
|
||||
|
||||
Monochrome and multicolor icons are supported through `color` and `--icon-color-N`.
|
||||
|
||||
### Manually with `<svg><use>`
|
||||
|
||||
A good low-level method that provides full control over dimensions and colors. This is exactly what the React component uses under the hood.
|
||||
|
||||
How you obtain `spriteUrl` depends on the bundler.
|
||||
|
||||
**Vite:**
|
||||
|
||||
```tsx
|
||||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
**Webpack 5:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
**Next.js with Webpack 5 or Turbopack:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
After obtaining the URL, the icon is rendered the same way:
|
||||
|
||||
```tsx
|
||||
<svg width={24} height={24}>
|
||||
<use href={`${spriteUrl}#check`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
Vite, Webpack 5, and Next.js replace the source path with the final hashed asset URL automatically.
|
||||
|
||||
### With `<img>` - less efficient
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Done" />
|
||||
```
|
||||
|
||||
The SVG loads as an isolated image: its colors cannot be changed through `color` or `--icon-color-N`.
|
||||
|
||||
### With CSS `background-image` - less efficient
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Like `<img>`, this method does not allow you to control internal SVG colors. The path is specified relative to the CSS file, and Vite/Webpack replaces it with the final hashed URL during the build.
|
||||
Run it for the first time:
|
||||
|
||||
### With CSS mask - less efficient
|
||||
```bash
|
||||
npm run sprites
|
||||
```
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
The package will generate `AppIcon`, TypeScript types, and a separate SVG sprite.
|
||||
|
||||
### 4. Use it like a regular icon
|
||||
|
||||
```tsx
|
||||
import { AppIcon } from '@/ui/app-icons'
|
||||
|
||||
export default function SearchButton() {
|
||||
return (
|
||||
<button type="button">
|
||||
<AppIcon icon="search" width={20} height={20} />
|
||||
Search
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
A mask retains only the silhouette and colors it with a single color. The original colors, gradients, and distinctions between `fill` and `stroke` are lost.
|
||||
This is a Server Component. The icon does not require a provider, `'use client'`, or manual URL construction.
|
||||
|
||||
## Transformations
|
||||
## Typed React component with autocomplete
|
||||
|
||||
All transformations are enabled by default and configured independently through `transform`.
|
||||
Each sprite gets its own ready-to-use component. The `icon` prop is derived from the actual SVG names, so your editor shows the exact list of available icons and TypeScript catches typos immediately.
|
||||
|
||||
| Option | Default | What it does |
|
||||
|---|---|---|
|
||||
| `removeSize` | `true` | Removes `width` and `height` from the root `<svg>` while preserving the existing `viewBox`. The icon size is then set externally. |
|
||||
| `replaceColors` | `true` | Replaces `fill` and `stroke` colors with `--icon-color-N`. For a monochrome icon, the fallback becomes `currentColor`; for a multicolor icon, the original colors are preserved. |
|
||||
| `addTransition` | `true` | Adds `style="transition:fill 0.3s,stroke 0.3s;"` directly to colored SVG elements. An existing `transition` is not overwritten. |
|
||||
|
||||
To disable a transformation, pass `false` for the corresponding option. For more details about the result of `replaceColors`, see [Icon color management](#icon-color-management).
|
||||
|
||||
## Icon color management
|
||||
|
||||
When color replacement is enabled, the generator analyzes `fill` and `stroke` and converts them to CSS custom properties.
|
||||
|
||||
### Monochrome icons
|
||||
|
||||
If one color is found, the fallback is replaced with `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```tsx
|
||||
<AppIcon icon="search" /> // available icon
|
||||
<AppIcon icon="serach" /> // TypeScript error
|
||||
```
|
||||
|
||||
The color is controlled by the CSS `color` property of the outer `<svg>` or its parent.
|
||||
After you add a new SVG icon and run generation again, its name automatically appears in the types and autocomplete. There is no need to maintain components, union types, or a name registry manually.
|
||||
|
||||
### Multicolor icons
|
||||
## Next.js App Router and SSR out of the box
|
||||
|
||||
Each unique color gets a separate variable with the original fallback:
|
||||
Generated components work in Server Components, SSR, and SSG without `'use client'`.
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
Using an icon does not turn the page into a Client Component, require a provider, or create an additional hydration boundary.
|
||||
|
||||
The same component can be used in `page.tsx`, `layout.tsx`, and both server and client components.
|
||||
|
||||
## Multiple sprites instead of one global sprite
|
||||
|
||||
Your project is not limited to a single icon set. Create independent sprites for shared elements, individual pages, and large UI modules.
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AnalyticsIcon icon="chart" />
|
||||
<EditorIcon icon="bold" />
|
||||
```
|
||||
|
||||
The page can override only the required colors:
|
||||
Each set gets its own typed component and SVG asset, so application sections do not load icons they do not need.
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
}
|
||||
```
|
||||
## Store each icon only once
|
||||
|
||||
### Color limitations
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced;
|
||||
- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably;
|
||||
- CSS classes and external stylesheets inside the source SVG are not the primary transformation use case;
|
||||
- gradients, patterns, filters, and `url(#...)` values require separate verification and may be incompatible with automatic color replacement;
|
||||
- page CSS variables are available with `<svg><use>`, but are not available inside `<img>` and `background-image`.
|
||||
|
||||
## Caching
|
||||
|
||||
The Vite, Webpack, and Next.js targets emit the sprite as a separate asset with a content hash:
|
||||
Each SVG icon is stored once in the source library and can be included in any number of sprites. Shared icons do not need to be copied between pages and modules: a single source updates every set.
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
search.svg ─┬─→ AppIcon
|
||||
├─→ AnalyticsIcon
|
||||
└─→ EditorIcon
|
||||
```
|
||||
|
||||
This provides the following properties:
|
||||
Sprites are split for performance, while the source icon library remains unified.
|
||||
|
||||
- the SVG is cached independently of JavaScript;
|
||||
- changes to React code do not alter the sprite contents;
|
||||
- icon changes produce a new hashed asset;
|
||||
- one file is used by every instance of the generated component;
|
||||
- SVG path data is absent from JavaScript chunks.
|
||||
## Browser caching
|
||||
|
||||
The Vite target prevents inlining through `?no-inline`. The Webpack 5 target uses Asset Modules through `new URL(..., import.meta.url)`.
|
||||
With a standard Vite, Webpack, or Next.js configuration, each sprite is emitted as a separate versioned SVG file.
|
||||
|
||||
## SpriteViewer
|
||||
As long as the icon set does not change, the browser can reuse its cached copy independently of JavaScript application updates.
|
||||
|
||||
`SpriteViewer` is a React component for viewing generated sprites inside an application's debug route.
|
||||
Changes to React components do not require downloading the geometry of every icon again.
|
||||
|
||||
It uses separate manifests and displays:
|
||||
## JavaScript without SVG bloat
|
||||
|
||||
- sprite groups;
|
||||
- the icon list and count;
|
||||
- search and the system light/dark theme;
|
||||
- a preview modal with the `viewBox` and color variable controls;
|
||||
- React, SVG, IMG, and CSS examples with code copying.
|
||||
Icon paths remain in external SVG assets and do not add to application chunks.
|
||||
|
||||
Production components do not import debug manifests. How you integrate the Viewer depends on the bundler:
|
||||
|
||||
- [React + Vite: automatic `import.meta.glob`](docs/en/react-vite.md#6-add-a-debug-page);
|
||||
- [React + Webpack 5: static `import()`](docs/en/react-webpack.md#6-add-a-debug-page);
|
||||
- [Next.js App Router](docs/en/next-app.md#5-add-spriteviewer);
|
||||
- [Next.js Pages Router](docs/en/next-pages.md#5-add-spriteviewer).
|
||||
|
||||
The Viewer is imported from the separate `@gromlab/svg-sprites/react` client entry point and is not included in production icon components.
|
||||
|
||||
### Viewer theme
|
||||
|
||||
By default, `colorTheme="auto"`: the Viewer follows `prefers-color-scheme` and responds to system theme changes. The application theme can be passed explicitly:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```text
|
||||
React code → JavaScript chunks
|
||||
SVG icons → separate SVG assets
|
||||
```
|
||||
|
||||
Valid `colorTheme` values are `auto`, `light`, and `dark`. When the theme is controlled externally, the built-in switch is hidden. To keep it and update the application theme through the Viewer, pass a callback:
|
||||
JavaScript handles the interface and behavior, while graphics are loaded and cached separately.
|
||||
|
||||
## Built-in SVG transformations
|
||||
|
||||
During generation, the package automatically prepares source SVG files for use in the UI:
|
||||
|
||||
- removes fixed `width` and `height` attributes;
|
||||
- preserves the existing `viewBox`;
|
||||
- converts `fill` and `stroke` values to CSS variables;
|
||||
- adds smooth transitions directly to colored icon elements.
|
||||
|
||||
Each transformation can be configured or disabled independently.
|
||||
|
||||
## Control every color with CSS
|
||||
|
||||
During generation, `fill` and `stroke` colors are automatically converted to `--icon-color-N` CSS variables.
|
||||
|
||||
A monochrome icon inherits `currentColor`:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
For a multicolor icon, each color can be changed independently:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Create themes, states, and hover effects without editing the SVG or making additional copies of the icon.
|
||||
|
||||
## SpriteViewer: every sprite on one debug page
|
||||
|
||||
`SpriteViewer` renders all project sprites in one place and shows which icons are included in each set and how they look.
|
||||
|
||||
For each icon, you can see the generated CSS variables and their fallback colors. Change the values directly in the Viewer and see the result immediately.
|
||||
|
||||
It also provides ready-to-use integration examples for:
|
||||
|
||||
- React;
|
||||
- `<svg><use>`;
|
||||
- `<img>`;
|
||||
- CSS.
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||
At its core is a standard SVG sprite that can be used even without a framework or bundler.
|
||||
|
||||
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
|
||||
|
||||
The generator creates a local `.gitignore` that excludes generated files and keeps them from cluttering project history, pull requests, and the codebase.
|
||||
|
||||
The repository contains the source SVG files, configuration, and `.gitignore` rule, while sprites, components, and types are regenerated locally and in CI through `prebuild`.
|
||||
|
||||
## Only icons in production
|
||||
|
||||
`@gromlab/svg-sprites` does its main work during generation and remains in `devDependencies`.
|
||||
|
||||
Production components use only local generated code, styles, and the external SVG file. The compiler and CLI are not bundled into the client application, while `SpriteViewer` is imported separately only where a debug page is needed.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
This README introduces the project's capabilities and demonstrates the primary use case. For setup, choose the guide for your stack.
|
||||
|
||||
### Quick start
|
||||
|
||||
- [Next.js App Router](docs/en/next-app.md)
|
||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||
- [Legacy mode](docs/en/legacy.md)
|
||||
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
- [Native HTML and classic SVG sprites](docs/en/legacy.md)
|
||||
|
||||
### Technical resources
|
||||
|
||||
- [Technical reference](docs/en/reference.md)
|
||||
- [Programmatic API](docs/en/programmatic-api.md)
|
||||
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
525
README_RU.md
525
README_RU.md
@@ -4,400 +4,261 @@
|
||||
|
||||
 
|
||||
|
||||
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
||||
`@gromlab/svg-sprites` — генератор SVG-спрайтов для современных веб-приложений. Он собирает выбранные SVG-иконки в один или несколько внешних кешируемых спрайтов и подготавливает их для использования в интерфейсе.
|
||||
|
||||

|
||||
Для React и Next.js пакет создаёт типизированные компоненты и поддерживает Vite, Webpack 5 и Turbopack. В основе при этом остаётся обычный SVG-спрайт, который можно использовать без фреймворка, в том числе в нативном HTML.
|
||||
|
||||
## AI-скиллы
|
||||
## SVG-спрайт так же прост, как обычная SVG-иконка
|
||||
|
||||
- [🇬🇧 Скачать английский скилл (последняя версия)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites.zip)
|
||||
- [🇷🇺 Скачать русский скилл (последняя версия)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites-ru.zip)
|
||||
Для всего спрайта генерируется один типизированный React-компонент. Выберите иконку через `icon`, а редактор покажет автокомплит всех доступных имён.
|
||||
|
||||
## Навигация
|
||||
|
||||
- [AI-скиллы](#ai-скиллы)
|
||||
- [Возможности](#возможности)
|
||||
- [Таблица поддержки](#таблица-поддержки)
|
||||
- [Требования](#требования)
|
||||
- [Быстрый старт](#быстрый-старт)
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
- [Next.js App Router](docs/ru/next-app.md)
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||
- [Конфигурация](#конфигурация)
|
||||
- [React](#react)
|
||||
- [Next.js](#nextjs)
|
||||
- [Множественные спрайты](#множественные-спрайты)
|
||||
- [TypeScript](#typescript)
|
||||
- [Форматы спрайтов](#форматы-спрайтов)
|
||||
- [Способы отображения](#способы-отображения)
|
||||
- [Трансформации](#трансформации)
|
||||
- [Управление цветом иконок](#управление-цветом-иконок)
|
||||
- [Кеширование](#кеширование)
|
||||
- [SpriteViewer](#spriteviewer)
|
||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
||||
- [Документация](#документация)
|
||||
|
||||
## Возможности
|
||||
|
||||
- **AI-agent friendly** — репозиторий содержит готовый skill с актуальной документацией для настройки, миграции и диагностики `@gromlab/svg-sprites`.
|
||||
- **TypeScript-friendly** — типизированные React-компоненты, union-типы и runtime-списки доступных иконок.
|
||||
- **Чистая генерация** — generated-файлы автоматически исключаются из Git, спрайт не нужно вручную размещать в `public`, а генератор обновляет только принадлежащие ему файлы.
|
||||
- **Общие иконки без копирования** — SVG из локальной папки и `inputFiles` объединяются в один спрайт; один файл можно использовать в нескольких спрайтах.
|
||||
- **Встроенное интерактивное превью** — `<SpriteViewer>` подключается как страница приложения и показывает переданные React- и Next.js-спрайты с поиском, настройкой цветов и примерами использования.
|
||||
- **Настраиваемые трансформации SVG** — удаление `width` и `height` с сохранением `viewBox`, замена исходных цветов на CSS-переменные и transitions для `fill` и `stroke`.
|
||||
- **Отдельный кешируемый SVG asset** — SVG path-данные не попадают в JavaScript chunks, а сборщик выпускает файл с content hash.
|
||||
- **Множественные спрайты** — независимые React- и Next.js-модули со своими компонентами, типами и SVG assets.
|
||||
- **Server-first Next.js** — generated-компоненты работают в Server Components, SSR и SSG без директивы `'use client'`.
|
||||
- **Форматы под разные сценарии** — React и Next.js используют `stack`, legacy-режим также поддерживает `symbol` для существующих интеграций.
|
||||
|
||||
## Таблица поддержки
|
||||
|
||||
| Среда | Ключ мода API | Статус |
|
||||
|---|---|---|
|
||||
| React + Vite | `react@vite` | Готово |
|
||||
| React + Webpack 5 | `react@webpack` | Готово |
|
||||
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Готово |
|
||||
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Готово |
|
||||
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Готово |
|
||||
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Готово |
|
||||
| Vue | — | Скоро |
|
||||
| Standalone | — | Скоро |
|
||||
|
||||
## Требования
|
||||
|
||||
- Node.js 18 или новее;
|
||||
- пакет распространяется только как ESM и подключается через `import`;
|
||||
- React 18 или 19 требуется только для generated-компонентов и точки входа `@gromlab/svg-sprites/react`;
|
||||
- для типизации subpath exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
Для быстрого старта воспользуйтесь инструкцией для вашего стека:
|
||||
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
- [Next.js App Router](docs/ru/next-app.md)
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||
|
||||
## Конфигурация
|
||||
|
||||
### React
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: [
|
||||
'../../shared/icons/check.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
| Опция | Тип | По умолчанию | Назначение |
|
||||
|---|---|---|---|
|
||||
| `name` | `string` | Имя папки | Имя спрайта, компонента и публичных типов |
|
||||
| `description` | `string` | Нет | Описание для типов и debug-манифеста |
|
||||
| `inputFolder` | `string` | `./icons` | Папка с исходными SVG относительно конфига |
|
||||
| `inputFiles` | `string[]` | `[]` | Дополнительные SVG-файлы относительно конфига |
|
||||
| `transform` | `TransformOptions` | Все включены | [Настройки трансформации](#трансформации) исходных SVG |
|
||||
| `generatedNotice` | `boolean` | `true` | Полное либо короткое предупреждение в generated-файлах |
|
||||
Компонент принимает привычные SVG-атрибуты: размеры, `color`, `className`, `style`, `aria-*` и обработчики событий. Если нужен внешний контейнер, добавьте `wrapped`.
|
||||
|
||||
`inputFolder` и `inputFiles` объединяются в один спрайт, поэтому один SVG-файл можно использовать в нескольких спрайтах без копирования. Если неявной папки `./icons` нет, но `inputFiles` заполнен, генерация продолжается только по списку. Явно указанная отсутствующая папка считается ошибкой. Одинаковые пути дедуплицируются, а разные файлы с одинаковым именем иконки считаются ошибкой.
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
`name` записывается в kebab-case и должно начинаться с латинской буквы. React и Next.js presets создают формат `stack`.
|
||||
В приложении не приходится работать со спрайтом напрямую. Вы используете его так же, как обычную SVG-иконку, но получаете один компонент, автокомплит и TypeScript-проверку всех имён.
|
||||
|
||||
### Next.js
|
||||
## AI-friendly из коробки
|
||||
|
||||
Next.js использует тот же `svg-sprite.config.ts` и набор опций. Для типизации можно использовать отдельный хелпер:
|
||||
`@gromlab/svg-sprites` сразу рассчитан на работу с AI-агентами. Подключите готовый skill и поручите агенту настройку, миграцию или диагностику без длинных инструкций и ручного изучения документации.
|
||||
|
||||
[🇷🇺 Скачать AI skill (на русском)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites-ru.zip)
|
||||
|
||||
[🇬🇧 Скачать AI skill (на английском)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites.zip)
|
||||
|
||||
## От SVG до компонента за четыре шага
|
||||
|
||||
Основной пример использует Next.js App Router и Turbopack.
|
||||
|
||||
### 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
### 2. Укажите нужные иконки
|
||||
|
||||
SVG могут оставаться в существующей структуре проекта:
|
||||
|
||||
```text
|
||||
src/
|
||||
├── assets/icons/
|
||||
│ ├── search.svg
|
||||
│ └── settings.svg
|
||||
├── features/profile/
|
||||
│ └── user.svg
|
||||
└── ui/app-icons/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Создайте конфигурацию спрайта:
|
||||
|
||||
```ts
|
||||
// src/ui/app-icons/svg-sprite.config.ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
name: 'app',
|
||||
inputFiles: [
|
||||
'../../assets/icons/search.svg',
|
||||
'../../assets/icons/settings.svg',
|
||||
'../../features/profile/user.svg',
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Роутер и сборщик выбираются через mode key, поэтому переключение между Turbopack и Webpack всегда явно отражено в команде генерации.
|
||||
### 3. Добавьте генерацию
|
||||
|
||||
## Множественные спрайты
|
||||
|
||||
Приложение может содержать несколько независимых спрайтов с разной областью использования:
|
||||
|
||||
**Проблема:** один глобальный спрайт загружает иконки, которые текущему экрану не нужны.
|
||||
|
||||
**Решение:** общие иконки хранить глобально, а наборы страниц и крупных компонентов — в отдельных спрайтах, загружаемых вместе с ними.
|
||||
|
||||
```text
|
||||
global → GlobalIcon → общие иконки приложения
|
||||
analytics-page → AnalyticsPageIcon → иконки отдельной страницы
|
||||
file-manager → FileManagerIcon → иконки крупного компонента
|
||||
```
|
||||
|
||||
- **Глобальный спрайт** содержит небольшие общие иконки, используемые в разных частях приложения: навигацию, состояния и базовые действия.
|
||||
- **Спрайт страницы** загружается вместе с конкретным разделом и не увеличивает общий спрайт иконками, которые больше нигде не нужны.
|
||||
- **Спрайт крупного компонента** инкапсулирует собственный набор иконок сложного UI-модуля, например файлового менеджера или редактора.
|
||||
|
||||
Каждая группа получает:
|
||||
|
||||
- собственный SVG asset;
|
||||
- собственный типизированный компонент;
|
||||
- отдельный список имён иконок;
|
||||
- отдельный debug-манифест;
|
||||
- независимый cache lifecycle.
|
||||
|
||||
|
||||
## TypeScript
|
||||
|
||||
Главная возможность TypeScript API — автодополнение имён иконок непосредственно в prop `icon`:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="folder" />
|
||||
// ↑ редактор предлагает все иконки спрайта
|
||||
```
|
||||
|
||||
Имена SVG-файлов становятся допустимыми значениями `icon`. Опечатка или неизвестное имя сразу становятся ошибкой TypeScript:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Для программного доступа generated-модуль экспортирует readonly-массив всех доступных иконок конкретного спрайта:
|
||||
|
||||
```ts
|
||||
import { fileManagerIconNames } from './svg-sprite'
|
||||
|
||||
// readonly ['check', 'folder', ...]
|
||||
```
|
||||
|
||||
Этот список можно использовать в собственных каталогах, select-компонентах, тестах и других runtime-сценариях. Из него также выводится union-тип `FileManagerIconName`.
|
||||
|
||||
Имена файлов с пробелами и другими небезопасными для SVG ID символами остаются частью публичного TypeScript API. Для внутреннего `<symbol id>` генератор создаёт стабильный hash ID.
|
||||
|
||||
```text
|
||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
Для таких имён используйте generated-компонент или `id` из debug-манифеста. Ручные примеры ниже с `#<имя>` подходят только для имён, которые уже являются безопасными SVG ID.
|
||||
|
||||
## Форматы спрайтов
|
||||
|
||||
`stack` — более современный формат, поэтому он используется по умолчанию. Иконки можно отображать через `<svg><use>`, `<img>` и CSS `background-image`.
|
||||
|
||||
`symbol` сохраняется для совместимости с существующими интеграциями и поддерживает отображение только через `<svg><use>`.
|
||||
|
||||
## Способы отображения
|
||||
|
||||
### React-компонент — рекомендуется
|
||||
|
||||
Generated-компонент предоставляет типизацию, автодополнение имён иконок и сам формирует URL SVG asset.
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="check" width={24} height={24} />
|
||||
```
|
||||
|
||||
Через `color` и `--icon-color-N` доступны одноцветные и многоцветные иконки.
|
||||
|
||||
### Самостоятельно через `<svg><use>`
|
||||
|
||||
Хороший низкоуровневый способ с полным управлением размерами и цветами. React-компонент под капотом использует именно его.
|
||||
|
||||
Способ получения `spriteUrl` зависит от сборщика.
|
||||
|
||||
**Vite:**
|
||||
|
||||
```tsx
|
||||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
**Webpack 5:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
**Next.js с Webpack 5 или Turbopack:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
После получения URL иконка отображается одинаково:
|
||||
|
||||
```tsx
|
||||
<svg width={24} height={24}>
|
||||
<use href={`${spriteUrl}#check`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
Vite, Webpack 5 и Next.js сами заменяют исходный путь на итоговый URL asset с hash.
|
||||
|
||||
### Через `<img>` — менее эффективно
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Готово" />
|
||||
```
|
||||
|
||||
SVG загружается как изолированное изображение: изменить его цвета через `color` или `--icon-color-N` нельзя.
|
||||
|
||||
### Через CSS `background-image` — менее эффективно
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Как и `<img>`, этот способ не позволяет управлять внутренними цветами SVG. Путь указывается относительно CSS-файла, а Vite/Webpack заменяет его на итоговый URL с hash при сборке.
|
||||
Первый запуск:
|
||||
|
||||
### Через CSS mask — менее эффективно
|
||||
```bash
|
||||
npm run sprites
|
||||
```
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
Пакет создаст `AppIcon`, TypeScript-типы и отдельный SVG-спрайт.
|
||||
|
||||
### 4. Используйте как обычную иконку
|
||||
|
||||
```tsx
|
||||
import { AppIcon } from '@/ui/app-icons'
|
||||
|
||||
export default function SearchButton() {
|
||||
return (
|
||||
<button type="button">
|
||||
<AppIcon icon="search" width={20} height={20} />
|
||||
Найти
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Mask оставляет только силуэт и окрашивает его одним цветом. Исходные цвета, gradients и различия между `fill` и `stroke` теряются.
|
||||
Это Server Component. Для иконки не нужны provider, `'use client'` или ручная сборка URL.
|
||||
|
||||
## Трансформации
|
||||
## Типизированный React-компонент с автокомплитом
|
||||
|
||||
Все трансформации включены по умолчанию и настраиваются независимо через `transform`.
|
||||
Каждый спрайт получает собственный готовый компонент. Свойство `icon` формируется из реальных имён SVG, поэтому редактор показывает точный список доступных иконок, а TypeScript сразу обнаруживает опечатки.
|
||||
|
||||
| Опция | По умолчанию | Что делает |
|
||||
|---|---|---|
|
||||
| `removeSize` | `true` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox`. Размер иконки после этого задаётся снаружи. |
|
||||
| `replaceColors` | `true` | Заменяет цвета `fill` и `stroke` на `--icon-color-N`. Для одноцветной иконки fallback становится `currentColor`, для многоцветной сохраняются исходные цвета. |
|
||||
| `addTransition` | `true` | Добавляет `style="transition:fill 0.3s,stroke 0.3s;"` непосредственно цветным элементам SVG. Существующий `transition` не перезаписывается. |
|
||||
|
||||
Чтобы отключить преобразование, передайте для соответствующей опции `false`. Подробнее о результате `replaceColors` — в разделе [«Управление цветом иконок»](#управление-цветом-иконок).
|
||||
|
||||
## Управление цветом иконок
|
||||
|
||||
При включённой замене цветов генератор анализирует `fill` и `stroke` и преобразует их в CSS custom properties.
|
||||
|
||||
### Монохромные иконки
|
||||
|
||||
Если найден один цвет, fallback заменяется на `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```tsx
|
||||
<AppIcon icon="search" /> // доступная иконка
|
||||
<AppIcon icon="serach" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
||||
После добавления новой SVG-иконки и повторной генерации её имя автоматически появляется в типах и автокомплите. Не нужно вручную поддерживать компоненты, union-типы или реестр имён.
|
||||
|
||||
### Многоцветные иконки
|
||||
## Next.js App Router и SSR из коробки
|
||||
|
||||
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
|
||||
Generated-компоненты работают в Server Components, SSR и SSG без `'use client'`.
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
Подключение иконки не переносит страницу на клиент, не требует provider и не создаёт дополнительную границу гидратации.
|
||||
|
||||
Один и тот же компонент можно использовать в `page.tsx`, `layout.tsx`, серверных и клиентских компонентах.
|
||||
|
||||
## Множественные спрайты вместо одного глобального
|
||||
|
||||
Проект не ограничен одним набором иконок. Создавайте независимые спрайты для общих элементов, отдельных страниц и крупных UI-модулей.
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AnalyticsIcon icon="chart" />
|
||||
<EditorIcon icon="bold" />
|
||||
```
|
||||
|
||||
Страница может заменить только необходимые цвета:
|
||||
Каждый набор получает собственный типизированный компонент и SVG asset, поэтому разделы приложения не несут иконки, которые им не нужны.
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
}
|
||||
```
|
||||
## Каждая иконка хранится в одном экземпляре
|
||||
|
||||
### Ограничения цветов
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
|
||||
- цвета в атрибутах `fill`, `stroke` и inline `style` обрабатываются надёжнее всего;
|
||||
- CSS-классы и внешние stylesheets внутри исходного SVG не являются основным сценарием трансформации;
|
||||
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
||||
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
||||
|
||||
## Кеширование
|
||||
|
||||
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
||||
В библиотеке исходников каждая SVG-иконка хранится в одном экземпляре и может входить в любое количество спрайтов. Общие иконки не приходится копировать между страницами и модулями: они обновляются для всех наборов из одного места.
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
search.svg ─┬─→ AppIcon
|
||||
├─→ AnalyticsIcon
|
||||
└─→ EditorIcon
|
||||
```
|
||||
|
||||
Это даёт следующие свойства:
|
||||
Спрайты разделяются ради производительности, но библиотека исходных иконок остаётся единой.
|
||||
|
||||
- SVG кешируется независимо от JavaScript;
|
||||
- изменение React-кода не меняет содержимое спрайта;
|
||||
- изменение иконок создаёт новый hash asset;
|
||||
- один файл используется всеми экземплярами generated-компонента;
|
||||
- SVG path-данные отсутствуют в JavaScript chunks.
|
||||
## Браузерное кеширование
|
||||
|
||||
Vite target запрещает inline через `?no-inline`. Webpack 5 target использует Asset Modules через `new URL(..., import.meta.url)`.
|
||||
При стандартной конфигурации Vite, Webpack или Next.js каждый спрайт выпускается отдельным версионированным SVG-файлом.
|
||||
|
||||
## SpriteViewer
|
||||
Пока набор иконок не меняется, браузер может использовать сохранённую копию независимо от обновлений JavaScript приложения.
|
||||
|
||||
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
||||
Изменение React-компонентов не требует повторно загружать геометрию всех иконок.
|
||||
|
||||
Он использует отдельные манифесты и показывает:
|
||||
## JavaScript без SVG-балласта
|
||||
|
||||
- группы спрайтов;
|
||||
- список и количество иконок;
|
||||
- поиск и системную светлую/тёмную тему;
|
||||
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
||||
- примеры React, SVG, IMG и CSS с копированием кода.
|
||||
Контуры иконок остаются во внешних SVG assets и не увеличивают chunks приложения.
|
||||
|
||||
Production-компоненты не импортируют debug-манифесты. Способ подключения Viewer зависит от сборщика:
|
||||
|
||||
- [React + Vite: автоматический `import.meta.glob`](docs/ru/react-vite.md#6-добавьте-debug-страницу);
|
||||
- [React + Webpack 5: статические `import()`](docs/ru/react-webpack.md#6-добавьте-debug-страницу);
|
||||
- [Next.js App Router](docs/ru/next-app.md#5-добавьте-spriteviewer);
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md#5-добавьте-spriteviewer).
|
||||
|
||||
Viewer подключается из отдельной клиентской точки входа `@gromlab/svg-sprites/react` и не попадает в production-компоненты иконок.
|
||||
|
||||
### Тема Viewer
|
||||
|
||||
По умолчанию `colorTheme="auto"`: Viewer следует `prefers-color-scheme` и реагирует на смену системной темы. Тему приложения можно передать явно:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```text
|
||||
React-код → JavaScript chunks
|
||||
SVG-иконки → отдельные SVG assets
|
||||
```
|
||||
|
||||
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
||||
JavaScript отвечает за интерфейс и поведение, а графика загружается и кешируется отдельно.
|
||||
|
||||
## Трансформации SVG из коробки
|
||||
|
||||
Во время генерации пакет автоматически подготавливает исходные SVG для интерфейса:
|
||||
|
||||
- удаляет фиксированные `width` и `height`;
|
||||
- сохраняет существующий `viewBox`;
|
||||
- преобразует `fill` и `stroke` в CSS-переменные;
|
||||
- добавляет плавные transitions непосредственно в цветные элементы иконки.
|
||||
|
||||
Каждую трансформацию можно настроить или отключить независимо.
|
||||
|
||||
## Каждый цвет под контролем CSS
|
||||
|
||||
При генерации цвета `fill` и `stroke` автоматически преобразуются в CSS-переменные `--icon-color-N`.
|
||||
|
||||
Монохромная иконка наследует `currentColor`:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
В многоцветной иконке каждый цвет можно менять отдельно:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Темы, состояния и hover-эффекты создаются без редактирования SVG и дополнительных копий иконки.
|
||||
|
||||
## SpriteViewer: все спрайты на одной debug-странице
|
||||
|
||||
`SpriteViewer` рендерит все спрайты проекта в одном месте и показывает, какие иконки вошли в каждый набор и как они выглядят.
|
||||
|
||||
Для каждой иконки видны созданные CSS-переменные и их fallback-цвета. Значения можно менять прямо в Viewer и сразу наблюдать результат.
|
||||
|
||||
Здесь же доступны готовые примеры подключения через:
|
||||
|
||||
- React;
|
||||
- `<svg><use>`;
|
||||
- `<img>`;
|
||||
- CSS.
|
||||
|
||||

|
||||
|
||||
Viewer подключается только к внутренней debug-странице и не становится частью generated-компонентов иконок.
|
||||
|
||||
## От нативного HTML до Next.js
|
||||
|
||||
В основе остаётся обычный SVG-спрайт, который можно использовать даже без фреймворка и сборщика.
|
||||
|
||||
Для React и Next.js пакет генерирует типизированные компоненты и поддерживает Vite, Webpack 5 и Turbopack. Список готовых интеграций будет расширяться новыми фреймворками.
|
||||
|
||||
## Чистый Git
|
||||
|
||||
Генератор создаёт локальный `.gitignore`, который исключает generated-файлы и не позволяет им засорять историю, pull requests и код проекта.
|
||||
|
||||
В репозитории остаются исходные SVG, конфигурация и правило `.gitignore`, а локально и в CI спрайты, компоненты и типы заново создаются через `prebuild`.
|
||||
|
||||
## В production только иконки
|
||||
|
||||
`@gromlab/svg-sprites` выполняет основную работу на этапе генерации и остаётся в `devDependencies`.
|
||||
|
||||
Production-компоненты используют только локальный generated-код, стили и внешний SVG-файл. Compiler и CLI не попадают в клиентское приложение, а `SpriteViewer` подключается отдельно только там, где нужна debug-страница.
|
||||
|
||||
## Документация
|
||||
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
README знакомит с возможностями проекта и показывает основной сценарий использования. Для настройки выберите руководство под свой стек.
|
||||
|
||||
### Быстрый старт
|
||||
|
||||
- [Next.js App Router](docs/ru/next-app.md)
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||
- [Legacy mode](docs/ru/legacy.md)
|
||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
- [Нативный HTML и классические SVG-спрайты](docs/ru/legacy.md)
|
||||
|
||||
### Технические материалы
|
||||
|
||||
- [Технический справочник](docs/ru/reference.md)
|
||||
- [Программный API](docs/ru/programmatic-api.md)
|
||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
||||
|
||||
## Лицензия
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ A quick guide to generating centralized SVG sprites in `symbol` and `stack` form
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Prepare the icons and config
|
||||
@@ -37,10 +37,21 @@ export default defineLegacyConfig({
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Run generation
|
||||
## 3. Add generation
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run the local package through the script:
|
||||
|
||||
```bash
|
||||
npx svg-sprites --mode legacy .
|
||||
npm run sprites
|
||||
```
|
||||
|
||||
Result:
|
||||
@@ -61,17 +72,6 @@ With `preview: false`, the HTML file is not created. For the `stack` format, spe
|
||||
</svg>
|
||||
```
|
||||
|
||||
## 5. Add a package script
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Multiple sprites
|
||||
|
||||
Add multiple entries to `sprites`:
|
||||
|
||||
@@ -4,13 +4,21 @@
|
||||
|
||||
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
|
||||
svg-sprites
|
||||
→ svg-sprites --mode <mode> <path>
|
||||
"sprites": "svg-sprites"
|
||||
→ "sprites": "svg-sprites --mode <mode> <path>"
|
||||
```
|
||||
|
||||
Choose a mode based on your environment:
|
||||
@@ -40,6 +48,18 @@ export default defineNextSpriteConfig({
|
||||
|
||||
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`:
|
||||
@@ -76,12 +96,18 @@ export default defineLegacyConfig({
|
||||
- `loadConfig` has been replaced with `loadLegacyConfig`;
|
||||
- `publicPath` and generation of the old shared React component have been removed.
|
||||
|
||||
Run:
|
||||
Add the local CLI to `package.json`:
|
||||
|
||||
```bash
|
||||
svg-sprites --mode legacy .
|
||||
```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`.
|
||||
@@ -90,7 +116,7 @@ The package is distributed as ESM only. Replace `require()` with `import`.
|
||||
|
||||
## After migration
|
||||
|
||||
1. Remove the old generated files and rules that ignored the entire directory containing the source icons.
|
||||
2. Add an explicit generation command before `dev`, `build`, and `typecheck`.
|
||||
3. Run generation and type checking.
|
||||
4. Check all icons and color variables using `SpriteViewer` or the legacy `preview.html`.
|
||||
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.
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
Two explicit modes are supported:
|
||||
|
||||
| Bundler | Mode key | Next.js version |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@app/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@app/webpack` | 13.4+ |
|
||||
| Bundler | Mode key |
|
||||
|---|---|
|
||||
| Turbopack | `next@app/turbopack` |
|
||||
| Webpack 5 | `next@app/webpack` |
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create a sprite module
|
||||
@@ -49,7 +49,13 @@ For Turbopack:
|
||||
}
|
||||
```
|
||||
|
||||
For Webpack, replace the mode key with `next@app/webpack`. In Next 13–15, Webpack is used with the regular `next build` command; in Next 16, use `next build --webpack`.
|
||||
For Webpack, replace the mode key with `next@app/webpack`.
|
||||
|
||||
Run the first generation before importing the generated module:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 4. Use it in a Server Component
|
||||
|
||||
@@ -89,14 +95,10 @@ export default function SpritesPage() {
|
||||
|
||||
## Verify the bundler
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
Run the project's build script configured for the selected bundler:
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
For Next 13–15 with Webpack, use `npx next build` without the flag.
|
||||
|
||||
The Next.js command and the generator mode key must target the same bundler.
|
||||
The build script and the generator mode key must target the same bundler.
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
|
||||
Two explicit modes are supported:
|
||||
|
||||
| Bundler | Mode key | Next.js version |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@pages/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@pages/webpack` | 12.2+ |
|
||||
|
||||
Next.js 12.2 requires React 18.
|
||||
| Bundler | Mode key |
|
||||
|---|---|
|
||||
| Turbopack | `next@pages/turbopack` |
|
||||
| Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create a sprite module
|
||||
@@ -49,7 +47,13 @@ export default defineNextSpriteConfig({
|
||||
}
|
||||
```
|
||||
|
||||
For Next.js 16.2 with Turbopack, replace the mode key with `next@pages/turbopack`.
|
||||
For Turbopack, replace the mode key with `next@pages/turbopack`.
|
||||
|
||||
Run the first generation before importing the generated module:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 4. Use it on a page
|
||||
|
||||
@@ -83,14 +87,10 @@ export default function SpritesPage() {
|
||||
|
||||
## Verify the bundler
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
Run the project's build script configured for the selected bundler:
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
For Next 12–15 with Webpack, use `npx next build` without the flag.
|
||||
|
||||
The Next.js command and the generator mode key must target the same bundler.
|
||||
The build script and the generator mode key must target the same bundler.
|
||||
|
||||
@@ -9,7 +9,7 @@ The result is a typed React component and a separate cacheable SVG asset.
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create the sprite directory
|
||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
||||
|
||||
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 [Configuration → React](../../README.md#react).
|
||||
The complete list of options is available under [React and Next.js configuration](reference.md#react-and-nextjs-configuration).
|
||||
|
||||
## 4. Add generation to package.json
|
||||
|
||||
@@ -83,7 +83,7 @@ TypeScript checks the `icon` value against the file names:
|
||||
<FileManagerIcon icon="unknown" /> // TypeScript error
|
||||
```
|
||||
|
||||
Types, rendering methods, and color controls are described in the [main documentation](../../README.md#rendering-methods).
|
||||
Types, rendering methods, and color controls are described in the [technical reference](reference.md#react-component-and-typescript).
|
||||
|
||||
Vite emits the sprite as a separate file named like `assets/sprite-<hash>.svg`. SVG path data is not included in JavaScript.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ The result is a typed React component and a separate SVG asset emitted through W
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create the sprite directory
|
||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
||||
|
||||
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 [Configuration → React](../../README.md#react).
|
||||
The complete list of options is available under [React and Next.js configuration](reference.md#react-and-nextjs-configuration).
|
||||
|
||||
## 4. Add generation to package.json
|
||||
|
||||
@@ -81,12 +81,14 @@ TypeScript checks the `icon` value against the file names:
|
||||
<FileManagerIcon icon="missing" /> // TypeScript error
|
||||
```
|
||||
|
||||
Types, rendering methods, and color controls are described in the [main documentation](../../README.md#rendering-methods).
|
||||
Types, rendering methods, and color controls are described in the [technical reference](reference.md#react-component-and-typescript).
|
||||
|
||||
Webpack processes the generated `new URL('./sprite.svg', import.meta.url)` through Asset Modules and emits a separate SVG asset.
|
||||
|
||||
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.
|
||||
|
||||
## 6. Add a debug page
|
||||
|
||||
Webpack does not support Vite's `import.meta.glob` API, so provide static loaders:
|
||||
|
||||
484
docs/en/reference.md
Normal file
484
docs/en/reference.md
Normal file
@@ -0,0 +1,484 @@
|
||||
# Technical reference
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
Reference for the configuration, generated API, and behavior of `@gromlab/svg-sprites`. For step-by-step setup instructions, see the guide for your stack:
|
||||
|
||||
- [Next.js App Router](next-app.md)
|
||||
- [Next.js Pages Router](next-pages.md)
|
||||
- [React + Vite](react-vite.md)
|
||||
- [React + Webpack 5](react-webpack.md)
|
||||
- [Native HTML and classic SVG sprites](legacy.md)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18 or newer;
|
||||
- the package is distributed as ESM and is loaded with `import`;
|
||||
- React 18 or 19 is required for generated components and `@gromlab/svg-sprites/react`;
|
||||
- for typed package exports, use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## CLI and generation modes
|
||||
|
||||
The CLI accepts one mode and a path to the configuration directory:
|
||||
|
||||
```text
|
||||
svg-sprites --mode <mode> <path>
|
||||
```
|
||||
|
||||
| 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` |
|
||||
| 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 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
|
||||
|
||||
Each directory containing `svg-sprite.config.ts` defines one independent sprite.
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'app',
|
||||
description: 'Shared application icons',
|
||||
inputFolder: './local-icons',
|
||||
inputFiles: [
|
||||
'../../assets/icons/search.svg',
|
||||
'../../assets/icons/settings.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
For React, use `defineReactSpriteConfig`. The configuration contract is the same:
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
| Option | Type | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `name` | `string` | Derived from the directory | Name of the sprite, component, and public types |
|
||||
| `description` | `string` | None | Description for types and the debug manifest |
|
||||
| `inputFolder` | `string` | `./icons` | SVG directory relative to the configuration file |
|
||||
| `inputFiles` | `string[]` | `[]` | Paths to individual SVG files relative to the configuration file |
|
||||
| `transform` | `TransformOptions` | All enabled | SVG preparation settings |
|
||||
| `generatedNotice` | `boolean` | `true` | Full or abbreviated warning in generated files |
|
||||
|
||||
### Sprite name
|
||||
|
||||
`name` is written in kebab-case and must start with an ASCII letter:
|
||||
|
||||
```text
|
||||
app → AppIcon
|
||||
file-manager → FileManagerIcon
|
||||
```
|
||||
|
||||
If `name` is omitted, the generator derives it from the directory. For a directory named `svg-sprite` or `svg-sprites`, the parent directory's name is used.
|
||||
|
||||
### Icon sources
|
||||
|
||||
`inputFolder` and `inputFiles` are combined into one set. This lets you keep local SVG files next to a module and add shared icons from other parts of the project without copying them.
|
||||
|
||||
If `inputFiles` is populated and the implicit `./icons` directory does not exist, generation uses only the file list. An explicitly configured `inputFolder` that does not exist is an error.
|
||||
|
||||
Only the top level of the directory is scanned. Nested directories are not traversed recursively. For a nested structure, list the exact paths through `inputFiles`.
|
||||
|
||||
Identical absolute paths are deduplicated. Different SVG files with the same file name are treated as a conflict because the public icon name is derived from the basename.
|
||||
|
||||
## Generated module
|
||||
|
||||
After generation, the sprite directory looks like this:
|
||||
|
||||
```text
|
||||
app-icons/
|
||||
├── .gitignore
|
||||
├── index.ts
|
||||
├── manifest.ts
|
||||
├── svg-sprite.config.ts
|
||||
└── generated/
|
||||
├── .svg-sprites.manifest.json
|
||||
├── react-component.tsx
|
||||
├── sprite.svg
|
||||
├── styles.module.css
|
||||
└── types.ts
|
||||
```
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `index.ts` | Production exports for the component, props, styles, and icon names |
|
||||
| `manifest.ts` | Debug metadata and the asset URL for `SpriteViewer` |
|
||||
| `generated/sprite.svg` | Compiled SVG sprite |
|
||||
| `generated/react-component.tsx` | Typed React component |
|
||||
| `generated/styles.module.css` | Base styles and transitions |
|
||||
| `generated/types.ts` | Runtime list and union type of icon names |
|
||||
| `generated/.svg-sprites.manifest.json` | List of files managed by the generator |
|
||||
|
||||
The generator overwrites and deletes only files that contain its marker. If a user file occupies a managed path, generation fails.
|
||||
|
||||
## React component and TypeScript
|
||||
|
||||
A sprite with `name: 'app'` exports:
|
||||
|
||||
```ts
|
||||
export { AppIcon, appIconNames }
|
||||
export type { AppIconName, AppIconProps, AppIconStyle }
|
||||
```
|
||||
|
||||
### Icon names
|
||||
|
||||
SVG file names become valid `icon` values:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AppIcon icon="unknown" /> // TypeScript error
|
||||
```
|
||||
|
||||
The runtime list contains the same values:
|
||||
|
||||
```ts
|
||||
import { appIconNames } from '@/ui/app-icons'
|
||||
|
||||
// readonly ['search', 'settings', 'user']
|
||||
```
|
||||
|
||||
Names containing spaces or other characters that are unsafe in SVG IDs remain part of the public API. For the internal fragment ID, the generator creates a stable, safe hash:
|
||||
|
||||
```text
|
||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
For these names, use the generated component or the `id` from the debug manifest instead of constructing the fragment ID manually.
|
||||
|
||||
### SVG attributes
|
||||
|
||||
By default, the component renders an `<svg>` and accepts standard SVG attributes:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="search"
|
||||
width={24}
|
||||
height={24}
|
||||
color="rebeccapurple"
|
||||
className="searchIcon"
|
||||
aria-label="Search"
|
||||
/>
|
||||
```
|
||||
|
||||
The component does not add accessibility semantics automatically. Pass appropriate `aria-*` attributes, a `role`, or a label based on the icon's purpose.
|
||||
|
||||
### Wrapper
|
||||
|
||||
`wrapped` renders a `<span>` containing the SVG. In this mode, the remaining props apply to the `<span>`:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
### Typed CSS custom properties
|
||||
|
||||
`AppIconStyle` extends `CSSProperties` and supports properties in the form `--icon-color-N`:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## Multiple sprites
|
||||
|
||||
Each directory with a configuration creates an independent component, types, manifest, and SVG asset:
|
||||
|
||||
```text
|
||||
app-icons → AppIcon → shared icons
|
||||
analytics-icons → AnalyticsIcon → analytics page icons
|
||||
editor-icons → EditorIcon → editor icons
|
||||
```
|
||||
|
||||
The same source SVG can be added to multiple configurations through `inputFiles`. You do not need to copy the file into each sprite directory.
|
||||
|
||||
For multiple sprites, add a separate CLI command for each directory or combine the commands in a shared npm script.
|
||||
|
||||
## Formats and rendering methods
|
||||
|
||||
Modern React and Next.js modes generate the `stack` format. Legacy mode supports both `stack` and `symbol`.
|
||||
|
||||
| Format | `<svg><use>` | `<img>` | CSS background |
|
||||
|---|---:|---:|---:|
|
||||
| `stack` | Yes | Yes | Yes |
|
||||
| `symbol` | Yes | No | No |
|
||||
|
||||
### Generated component
|
||||
|
||||
For React and Next.js, use the generated component. It knows the internal IDs, constructs the URL, and provides a TypeScript API:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
### Manually with `<svg><use>`
|
||||
|
||||
How you obtain `spriteUrl` depends on the bundler.
|
||||
|
||||
Vite:
|
||||
|
||||
```ts
|
||||
import spriteUrl from './generated/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
Webpack 5, Turbopack, and Next.js:
|
||||
|
||||
```ts
|
||||
const spriteUrl = new URL('./generated/sprite.svg', import.meta.url).href
|
||||
```
|
||||
|
||||
After obtaining the URL, use it in JSX:
|
||||
|
||||
```tsx
|
||||
<svg width="24" height="24" aria-label="Search">
|
||||
<use href={`${spriteUrl}#search`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
For names that are unsafe as SVG IDs, use the internal `id` from the manifest.
|
||||
|
||||
### With `<img>`
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#search`} width={24} height={24} alt="Search" />
|
||||
```
|
||||
|
||||
An SVG inside `<img>` is isolated from the page's CSS. Setting `color` or `--icon-color-N` on the outer element does not change its internal colors.
|
||||
|
||||
### With CSS
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./generated/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
For a single-color silhouette, you can use a mask:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./generated/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
A mask does not preserve original colors, gradients, or differences between `fill` and `stroke`.
|
||||
|
||||
The path in CSS is resolved relative to the CSS file itself. In these examples, the CSS file is next to `svg-sprite.config.ts`.
|
||||
|
||||
## Assets and caching
|
||||
|
||||
The generated component passes the SVG to the bundler as a separate asset:
|
||||
|
||||
- Vite uses a static import with `?no-inline`;
|
||||
- Webpack 5, Turbopack, and Next.js use `new URL(..., import.meta.url)`;
|
||||
- SVG path data is not serialized into the generated TSX.
|
||||
|
||||
With standard asset naming, the bundler adds a content hash:
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
```
|
||||
|
||||
This allows the SVG to be cached separately from JavaScript. Changing React code does not change the sprite contents, while changing icons creates a new asset version.
|
||||
|
||||
HTTP cache headers, CDN behavior, and `Cache-Control` are configured by the application or hosting platform. With Webpack, the final file name depends on the project's `assetModuleFilename`.
|
||||
|
||||
## SVG transformations
|
||||
|
||||
All transformations are enabled by default and can be configured independently:
|
||||
|
||||
| Option | Behavior |
|
||||
|---|---|
|
||||
| `removeSize` | Removes `width` and `height` from the root `<svg>` while preserving an existing `viewBox` |
|
||||
| `replaceColors` | Replaces detected `fill` and `stroke` values with `--icon-color-N` |
|
||||
| `addTransition` | Adds transitions for `fill` and `stroke` to colored elements and generated styles |
|
||||
|
||||
To disable an individual operation:
|
||||
|
||||
```ts
|
||||
export default defineNextSpriteConfig({
|
||||
transform: {
|
||||
removeSize: false,
|
||||
replaceColors: false,
|
||||
addTransition: false,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Source SVG files are not modified. Transformations apply only to the generated sprite contents.
|
||||
|
||||
## Color management
|
||||
|
||||
### Monochrome icons
|
||||
|
||||
If one color is detected, its fallback becomes `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```
|
||||
|
||||
Set the color through a prop or CSS:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
### Multicolor icons
|
||||
|
||||
Each unique color gets its own custom property with the original color as its fallback:
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
```
|
||||
|
||||
You can override only the values you need:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
}
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced;
|
||||
- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably;
|
||||
- CSS classes and external stylesheets inside the SVG are not the primary transformation use case;
|
||||
- `url(#...)` values may be replaced along with colors, so gradients and patterns require a separate sprite with `replaceColors: false`;
|
||||
- masks, filters, and complex internal CSS rules require visual verification;
|
||||
- page CSS custom properties are available through `<svg><use>`, but not inside `<img>` or a CSS background.
|
||||
|
||||
For a complex icon, you can disable `replaceColors` in a separate sprite configuration.
|
||||
|
||||
## SpriteViewer
|
||||
|
||||
`SpriteViewer` is imported from a separate client entry point:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
It accepts ready-made manifests, an array of lazy loaders, or a record in the format returned by `import.meta.glob`.
|
||||
|
||||
Vite:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = import.meta.glob<SpriteManifestModule>(
|
||||
'/src/**/svg-sprite/manifest.ts',
|
||||
)
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Project icons" />
|
||||
)
|
||||
```
|
||||
|
||||
Webpack and Next.js:
|
||||
|
||||
```tsx
|
||||
const sources = [
|
||||
() => import('@/ui/app-icons/manifest'),
|
||||
() => import('@/features/analytics/icons/manifest'),
|
||||
]
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} />
|
||||
)
|
||||
```
|
||||
|
||||
The Viewer displays groups, search, `viewBox`, CSS custom properties, fallback colors, and React, SVG, IMG, and CSS examples. You can change color values in the interface and immediately inspect the result.
|
||||
|
||||
### Viewer theme
|
||||
|
||||
By default, `colorTheme="auto"` follows `prefers-color-scheme`. You can explicitly pass `light` or `dark`:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```
|
||||
|
||||
To synchronize it with the application theme:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
/>
|
||||
```
|
||||
|
||||
`@gromlab/svg-sprites/react` contains `'use client'`. In the Next.js App Router, place the Viewer inside a separate Client Component boundary and use it only on a debug route or in an internal tool.
|
||||
|
||||
## Generated files, Git, and CI
|
||||
|
||||
A modern sprite module creates a local `.gitignore` for:
|
||||
|
||||
```text
|
||||
/generated/
|
||||
/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:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites",
|
||||
"pretypecheck": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Missing `index.ts`: run the generation script before importing the module.
|
||||
- Configuration not found: check the CLI path and the `svg-sprite.config.ts` file name.
|
||||
- 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.
|
||||
- `Refusing to overwrite a user file`: a file without the generated marker occupies a managed path.
|
||||
- The icon does not change color: use `<svg><use>` or the generated component and check `replaceColors`.
|
||||
- Webpack emits an incorrect URL: check Asset Modules, `output.publicPath`, and SVG loaders.
|
||||
- The Viewer cannot find the sprite: check the path to `manifest.ts` and run generation before starting the application.
|
||||
- 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).
|
||||
@@ -7,7 +7,7 @@
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Подготовьте иконки и конфиг
|
||||
@@ -37,10 +37,21 @@ export default defineLegacyConfig({
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Запустите генерацию
|
||||
## 3. Добавьте генерацию
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Запустите локально установленный пакет через script:
|
||||
|
||||
```bash
|
||||
npx svg-sprites --mode legacy .
|
||||
npm run sprites
|
||||
```
|
||||
|
||||
Результат:
|
||||
@@ -61,17 +72,6 @@ public/sprites/
|
||||
</svg>
|
||||
```
|
||||
|
||||
## 5. Добавьте package script
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Несколько спрайтов
|
||||
|
||||
Добавьте несколько записей в `sprites`:
|
||||
|
||||
@@ -4,13 +4,21 @@
|
||||
|
||||
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
||||
|
||||
## Установка
|
||||
|
||||
Установите пакет как development dependency, чтобы миграция использовала версию из lockfile проекта:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## CLI
|
||||
|
||||
CLI теперь всегда требует явный `--mode` и путь к каталогу конфигурации:
|
||||
|
||||
```text
|
||||
svg-sprites
|
||||
→ svg-sprites --mode <mode> <path>
|
||||
"sprites": "svg-sprites"
|
||||
→ "sprites": "svg-sprites --mode <mode> <path>"
|
||||
```
|
||||
|
||||
Выберите mode по окружению:
|
||||
@@ -40,6 +48,18 @@ export default defineNextSpriteConfig({
|
||||
|
||||
Для обычного 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`:
|
||||
@@ -76,12 +96,18 @@ export default defineLegacyConfig({
|
||||
- `loadConfig` заменён на `loadLegacyConfig`;
|
||||
- `publicPath` и генерация старого общего React-компонента удалены.
|
||||
|
||||
Запуск:
|
||||
Добавьте локальный CLI в `package.json`:
|
||||
|
||||
```bash
|
||||
svg-sprites --mode legacy .
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy ."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Запустите его командой `npm run sprites`.
|
||||
|
||||
## Программный API
|
||||
|
||||
Пакет распространяется только как ESM. Замените `require()` на `import`.
|
||||
@@ -90,7 +116,7 @@ svg-sprites --mode legacy .
|
||||
|
||||
## После миграции
|
||||
|
||||
1. Удалите старые generated-файлы и правила, которые игнорировали целиком каталог с исходными иконками.
|
||||
2. Добавьте явную команду генерации перед `dev`, `build` и `typecheck`.
|
||||
3. Запустите генерацию и проверку типов.
|
||||
4. Проверьте все иконки и цветовые переменные через `SpriteViewer` или legacy `preview.html`.
|
||||
1. Добавьте явную команду генерации перед `dev`, `build` и `typecheck`.
|
||||
2. Создайте новый output и запустите проверку типов, пока старые artifacts остаются доступны.
|
||||
3. Замените imports и проверьте иконки и цветовые переменные через `SpriteViewer` или legacy `preview.html`.
|
||||
4. Только после этого удалите подтверждённые старые generated-файлы и устаревшие ignore rules, не затрагивая исходные SVG.
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
Поддерживаются два явных режима:
|
||||
|
||||
| Сборщик | Mode key | Версия Next.js |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@app/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@app/webpack` | 13.4+ |
|
||||
| Сборщик | Mode key |
|
||||
|---|---|
|
||||
| Turbopack | `next@app/turbopack` |
|
||||
| Webpack 5 | `next@app/webpack` |
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте sprite-модуль
|
||||
@@ -49,7 +49,13 @@ export default defineNextSpriteConfig({
|
||||
}
|
||||
```
|
||||
|
||||
Для Webpack замените mode key на `next@app/webpack`. В Next 13–15 Webpack используется обычной командой `next build`, в Next 16 — командой `next build --webpack`.
|
||||
Для Webpack замените mode key на `next@app/webpack`.
|
||||
|
||||
До импорта generated-модуля выполните первую генерацию:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 4. Используйте в Server Component
|
||||
|
||||
@@ -89,14 +95,10 @@ export default function SpritesPage() {
|
||||
|
||||
## Проверка сборщика
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
Запустите build script проекта, настроенный на выбранный сборщик:
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Для Next 13–15 с Webpack используйте `npx next build` без флага.
|
||||
|
||||
Команда Next.js и mode key генератора должны указывать один и тот же сборщик.
|
||||
Build script и mode key генератора должны указывать один и тот же сборщик.
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
|
||||
Поддерживаются два явных режима:
|
||||
|
||||
| Сборщик | Mode key | Версия Next.js |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@pages/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@pages/webpack` | 12.2+ |
|
||||
|
||||
Для Next.js 12.2 требуется React 18.
|
||||
| Сборщик | Mode key |
|
||||
|---|---|
|
||||
| Turbopack | `next@pages/turbopack` |
|
||||
| Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте sprite-модуль
|
||||
@@ -49,7 +47,13 @@ export default defineNextSpriteConfig({
|
||||
}
|
||||
```
|
||||
|
||||
Для Next.js 16.2 с Turbopack замените mode key на `next@pages/turbopack`.
|
||||
Для Turbopack замените mode key на `next@pages/turbopack`.
|
||||
|
||||
До импорта generated-модуля выполните первую генерацию:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 4. Используйте на странице
|
||||
|
||||
@@ -83,14 +87,10 @@ export default function SpritesPage() {
|
||||
|
||||
## Проверка сборщика
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
Запустите build script проекта, настроенный на выбранный сборщик:
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Для Next 12–15 с Webpack используйте `npx next build` без флага.
|
||||
|
||||
Команда Next.js и mode key генератора должны указывать один и тот же сборщик.
|
||||
Build script и mode key генератора должны указывать один и тот же сборщик.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте папку спрайта
|
||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
||||
|
||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||
|
||||
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||
Полный список опций находится в разделе [«Конфигурация React и Next.js»](reference.md#конфигурация-react-и-nextjs).
|
||||
|
||||
## 4. Добавьте генерацию в package.json
|
||||
|
||||
@@ -83,7 +83,7 @@ export const OpenFolderButton = () => (
|
||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||
Типы, способы отображения и управление цветами описаны в [техническом справочнике](reference.md#react-компонент-и-typescript).
|
||||
|
||||
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте папку спрайта
|
||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
||||
|
||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||
|
||||
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||
Полный список опций находится в разделе [«Конфигурация React и Next.js»](reference.md#конфигурация-react-и-nextjs).
|
||||
|
||||
## 4. Добавьте генерацию в package.json
|
||||
|
||||
@@ -81,12 +81,14 @@ export const OpenFolderButton = () => (
|
||||
<FileManagerIcon icon="missing" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||
Типы, способы отображения и управление цветами описаны в [техническом справочнике](reference.md#react-компонент-и-typescript).
|
||||
|
||||
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
|
||||
|
||||
Если проект уже использует собственный SVG loader, убедитесь, что он не перехватывает generated `sprite.svg` вместо Asset Modules.
|
||||
|
||||
Generated-компонент импортирует `styles.module.css`, поэтому Webpack должен обрабатывать CSS Modules через `css-loader` и `style-loader` либо `MiniCssExtractPlugin`. Если TypeScript-проект не содержит декларации для CSS Modules, добавьте её отдельно.
|
||||
|
||||
## 6. Добавьте debug-страницу
|
||||
|
||||
Webpack не поддерживает Vite API `import.meta.glob`, поэтому передайте статические loaders:
|
||||
|
||||
484
docs/ru/reference.md
Normal file
484
docs/ru/reference.md
Normal file
@@ -0,0 +1,484 @@
|
||||
# Технический справочник
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Справочник по конфигурации, generated API и поведению `@gromlab/svg-sprites`. Пошаговую установку смотрите в руководстве для вашего стека:
|
||||
|
||||
- [Next.js App Router](next-app.md)
|
||||
- [Next.js Pages Router](next-pages.md)
|
||||
- [React + Vite](react-vite.md)
|
||||
- [React + Webpack 5](react-webpack.md)
|
||||
- [Нативный HTML и классические SVG-спрайты](legacy.md)
|
||||
|
||||
## Требования
|
||||
|
||||
- Node.js 18 или новее;
|
||||
- пакет распространяется как ESM и подключается через `import`;
|
||||
- React 18 или 19 требуется для generated-компонентов и `@gromlab/svg-sprites/react`;
|
||||
- для типизации package exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||
|
||||
Пакет устанавливается как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## CLI и режимы генерации
|
||||
|
||||
CLI принимает один режим и путь к каталогу конфигурации:
|
||||
|
||||
```text
|
||||
svg-sprites --mode <mode> <path>
|
||||
```
|
||||
|
||||
| Среда | 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` |
|
||||
| Классические `stack`- и `symbol`-спрайты | `legacy` |
|
||||
|
||||
Современные React- и Next.js-режимы используют локальный `svg-sprite.config.ts`. Legacy-режим использует отдельный `svg-sprites.config.ts` и описан в [собственном руководстве](legacy.md).
|
||||
|
||||
Mode должен соответствовать сборщику приложения. Генератор создаёт разный способ подключения SVG asset для Vite и сборщиков, совместимых с Webpack Asset Modules.
|
||||
|
||||
## Конфигурация React и Next.js
|
||||
|
||||
Каждый каталог с `svg-sprite.config.ts` описывает один независимый спрайт.
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'app',
|
||||
description: 'Общие иконки приложения',
|
||||
inputFolder: './local-icons',
|
||||
inputFiles: [
|
||||
'../../assets/icons/search.svg',
|
||||
'../../assets/icons/settings.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
Для React используйте `defineReactSpriteConfig`. Контракт конфигурации одинаковый:
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
| Опция | Тип | По умолчанию | Назначение |
|
||||
|---|---|---|---|
|
||||
| `name` | `string` | Выводится из каталога | Имя спрайта, компонента и публичных типов |
|
||||
| `description` | `string` | Нет | Описание для типов и debug manifest |
|
||||
| `inputFolder` | `string` | `./icons` | Каталог с SVG относительно конфига |
|
||||
| `inputFiles` | `string[]` | `[]` | Пути к отдельным SVG относительно конфига |
|
||||
| `transform` | `TransformOptions` | Все включены | Настройки подготовки SVG |
|
||||
| `generatedNotice` | `boolean` | `true` | Полное или короткое предупреждение в generated-файлах |
|
||||
|
||||
### Имя спрайта
|
||||
|
||||
`name` записывается в kebab-case и должно начинаться с латинской буквы:
|
||||
|
||||
```text
|
||||
app → AppIcon
|
||||
file-manager → FileManagerIcon
|
||||
```
|
||||
|
||||
Если `name` не задано, генератор выводит его из каталога. Для каталога с именем `svg-sprite` или `svg-sprites` используется имя родительского каталога.
|
||||
|
||||
### Источники иконок
|
||||
|
||||
`inputFolder` и `inputFiles` объединяются в один набор. Это позволяет хранить локальные SVG рядом с модулем и добавлять общие иконки из других частей проекта без копирования.
|
||||
|
||||
Если `inputFiles` заполнен, а неявного каталога `./icons` нет, генерация работает только по списку файлов. Явно указанная отсутствующая `inputFolder` считается ошибкой.
|
||||
|
||||
Каталог сканируется только на первом уровне. Вложенные каталоги рекурсивно не обходятся. Для вложенной структуры перечислите точные пути через `inputFiles`.
|
||||
|
||||
Одинаковые абсолютные пути дедуплицируются. Разные SVG с одинаковым именем файла считаются конфликтом, потому что публичное имя иконки выводится из basename.
|
||||
|
||||
## Generated-модуль
|
||||
|
||||
После генерации каталог спрайта выглядит так:
|
||||
|
||||
```text
|
||||
app-icons/
|
||||
├── .gitignore
|
||||
├── index.ts
|
||||
├── manifest.ts
|
||||
├── svg-sprite.config.ts
|
||||
└── generated/
|
||||
├── .svg-sprites.manifest.json
|
||||
├── react-component.tsx
|
||||
├── sprite.svg
|
||||
├── styles.module.css
|
||||
└── types.ts
|
||||
```
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `index.ts` | Production exports компонента, props, стилей и имён иконок |
|
||||
| `manifest.ts` | Debug metadata и URL asset для `SpriteViewer` |
|
||||
| `generated/sprite.svg` | Собранный SVG-спрайт |
|
||||
| `generated/react-component.tsx` | Типизированный React-компонент |
|
||||
| `generated/styles.module.css` | Базовые стили и transitions |
|
||||
| `generated/types.ts` | Runtime-список и union-тип имён |
|
||||
| `generated/.svg-sprites.manifest.json` | Список файлов, которыми управляет генератор |
|
||||
|
||||
Генератор перезаписывает и удаляет только файлы со своим marker. Если в managed-пути находится пользовательский файл, генерация завершается ошибкой.
|
||||
|
||||
## React-компонент и TypeScript
|
||||
|
||||
Спрайт с `name: 'app'` экспортирует:
|
||||
|
||||
```ts
|
||||
export { AppIcon, appIconNames }
|
||||
export type { AppIconName, AppIconProps, AppIconStyle }
|
||||
```
|
||||
|
||||
### Имена иконок
|
||||
|
||||
Имена SVG-файлов становятся допустимыми значениями `icon`:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AppIcon icon="unknown" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Runtime-список содержит те же значения:
|
||||
|
||||
```ts
|
||||
import { appIconNames } from '@/ui/app-icons'
|
||||
|
||||
// readonly ['search', 'settings', 'user']
|
||||
```
|
||||
|
||||
Имена с пробелами и другими небезопасными для SVG ID символами остаются частью публичного API. Для внутреннего fragment ID генератор создаёт стабильный безопасный hash:
|
||||
|
||||
```text
|
||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
Для таких имён используйте generated-компонент или `id` из debug manifest, а не формируйте fragment ID вручную.
|
||||
|
||||
### SVG-атрибуты
|
||||
|
||||
По умолчанию компонент рендерит `<svg>` и принимает стандартные SVG-атрибуты:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="search"
|
||||
width={24}
|
||||
height={24}
|
||||
color="rebeccapurple"
|
||||
className="searchIcon"
|
||||
aria-label="Поиск"
|
||||
/>
|
||||
```
|
||||
|
||||
Компонент не добавляет accessibility-семантику автоматически. Передавайте подходящие `aria-*`, `role` или подпись в зависимости от назначения иконки.
|
||||
|
||||
### Обёртка
|
||||
|
||||
`wrapped` рендерит `<span>` с внутренним SVG. Остальные props в этом режиме относятся к `<span>`:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
### Типизированные CSS-переменные
|
||||
|
||||
`AppIconStyle` расширяет `CSSProperties` и поддерживает свойства вида `--icon-color-N`:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## Множественные спрайты
|
||||
|
||||
Каждый каталог с конфигом создаёт независимый компонент, типы, manifest и SVG asset:
|
||||
|
||||
```text
|
||||
app-icons → AppIcon → общие иконки
|
||||
analytics-icons → AnalyticsIcon → иконки страницы аналитики
|
||||
editor-icons → EditorIcon → иконки редактора
|
||||
```
|
||||
|
||||
Один исходный SVG можно добавить через `inputFiles` в несколько конфигураций. Копировать файл в каталоги каждого спрайта не требуется.
|
||||
|
||||
Для нескольких спрайтов добавьте отдельную CLI-команду для каждого каталога или объедините команды в общем npm script.
|
||||
|
||||
## Форматы и способы отображения
|
||||
|
||||
Современные React- и Next.js-режимы создают формат `stack`. Legacy-режим поддерживает `stack` и `symbol`.
|
||||
|
||||
| Формат | `<svg><use>` | `<img>` | CSS background |
|
||||
|---|---:|---:|---:|
|
||||
| `stack` | Да | Да | Да |
|
||||
| `symbol` | Да | Нет | Нет |
|
||||
|
||||
### Generated-компонент
|
||||
|
||||
Для React и Next.js используйте generated-компонент. Он знает внутренние ID, формирует URL и предоставляет TypeScript API:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
### Вручную через `<svg><use>`
|
||||
|
||||
Способ получения `spriteUrl` зависит от сборщика.
|
||||
|
||||
Vite:
|
||||
|
||||
```ts
|
||||
import spriteUrl from './generated/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
Webpack 5, Turbopack и Next.js:
|
||||
|
||||
```ts
|
||||
const spriteUrl = new URL('./generated/sprite.svg', import.meta.url).href
|
||||
```
|
||||
|
||||
После получения URL используйте его в JSX:
|
||||
|
||||
```tsx
|
||||
<svg width="24" height="24" aria-label="Поиск">
|
||||
<use href={`${spriteUrl}#search`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
Для имён, небезопасных как SVG ID, используйте внутренний `id` из manifest.
|
||||
|
||||
### Через `<img>`
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#search`} width={24} height={24} alt="Поиск" />
|
||||
```
|
||||
|
||||
SVG внутри `<img>` изолирован от CSS страницы. `color` и `--icon-color-N` на внешнем элементе не изменяют его внутренние цвета.
|
||||
|
||||
### Через CSS
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./generated/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
Для одноцветного силуэта можно использовать mask:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./generated/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
Mask не сохраняет исходные цвета, gradients и различия между `fill` и `stroke`.
|
||||
|
||||
Путь в CSS разрешается относительно самого CSS-файла. В примерах CSS-файл находится рядом с `svg-sprite.config.ts`.
|
||||
|
||||
## Assets и кеширование
|
||||
|
||||
Generated-компонент передаёт SVG сборщику как отдельный asset:
|
||||
|
||||
- Vite использует статический импорт с `?no-inline`;
|
||||
- Webpack 5, Turbopack и Next.js используют `new URL(..., import.meta.url)`;
|
||||
- SVG path-данные не сериализуются в generated TSX.
|
||||
|
||||
При стандартном именовании assets сборщик добавляет content hash:
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
```
|
||||
|
||||
Это позволяет кешировать SVG отдельно от JavaScript. Изменение React-кода не меняет содержимое спрайта, а изменение иконок создаёт новую версию asset.
|
||||
|
||||
HTTP cache headers, CDN и `Cache-Control` настраиваются приложением или платформой размещения. Для Webpack имя итогового файла зависит от `assetModuleFilename` проекта.
|
||||
|
||||
## Трансформации SVG
|
||||
|
||||
Все трансформации включены по умолчанию и настраиваются независимо:
|
||||
|
||||
| Опция | Что делает |
|
||||
|---|---|
|
||||
| `removeSize` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox` |
|
||||
| `replaceColors` | Заменяет найденные `fill` и `stroke` на `--icon-color-N` |
|
||||
| `addTransition` | Добавляет transitions для `fill` и `stroke` в цветные элементы и generated styles |
|
||||
|
||||
Чтобы отключить отдельную операцию:
|
||||
|
||||
```ts
|
||||
export default defineNextSpriteConfig({
|
||||
transform: {
|
||||
removeSize: false,
|
||||
replaceColors: false,
|
||||
addTransition: false,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Исходные SVG не изменяются. Трансформации применяются только к содержимому generated-спрайта.
|
||||
|
||||
## Управление цветами
|
||||
|
||||
### Монохромные иконки
|
||||
|
||||
Если найден один цвет, fallback становится `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```
|
||||
|
||||
Цвет задаётся через prop или CSS:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
### Многоцветные иконки
|
||||
|
||||
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
```
|
||||
|
||||
Можно заменить только необходимые значения:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
}
|
||||
```
|
||||
|
||||
### Ограничения
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
|
||||
- надёжнее всего обрабатываются цвета в атрибутах `fill`, `stroke` и inline `style`;
|
||||
- CSS-классы и внешние stylesheets внутри SVG не являются основным сценарием трансформации;
|
||||
- значения `url(#...)` могут быть заменены вместе с цветами, поэтому gradients и patterns требуют отдельного спрайта с `replaceColors: false`;
|
||||
- masks, filters и сложные внутренние CSS-правила требуют визуальной проверки;
|
||||
- CSS-переменные страницы доступны через `<svg><use>`, но не внутри `<img>` и CSS background.
|
||||
|
||||
Для сложной иконки можно отключить `replaceColors` в конфигурации отдельного спрайта.
|
||||
|
||||
## SpriteViewer
|
||||
|
||||
`SpriteViewer` подключается из отдельной клиентской точки входа:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
Он принимает готовые manifests, массив lazy loaders или record формата `import.meta.glob`.
|
||||
|
||||
Vite:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = import.meta.glob<SpriteManifestModule>(
|
||||
'/src/**/svg-sprite/manifest.ts',
|
||||
)
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
)
|
||||
```
|
||||
|
||||
Webpack и Next.js:
|
||||
|
||||
```tsx
|
||||
const sources = [
|
||||
() => import('@/ui/app-icons/manifest'),
|
||||
() => import('@/features/analytics/icons/manifest'),
|
||||
]
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} />
|
||||
)
|
||||
```
|
||||
|
||||
Viewer показывает группы, поиск, `viewBox`, CSS-переменные, fallback-цвета и примеры React, SVG, IMG и CSS. Цветовые значения можно менять в интерфейсе и сразу проверять результат.
|
||||
|
||||
### Тема Viewer
|
||||
|
||||
По умолчанию `colorTheme="auto"` следует `prefers-color-scheme`. Можно передать `light` или `dark` явно:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```
|
||||
|
||||
Для синхронизации с темой приложения:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
/>
|
||||
```
|
||||
|
||||
`@gromlab/svg-sprites/react` содержит `'use client'`. В Next.js App Router размещайте Viewer внутри отдельной Client Component boundary и используйте только на debug-маршруте или во внутреннем инструменте.
|
||||
|
||||
## Generated-файлы, Git и CI
|
||||
|
||||
Современный sprite-модуль создаёт локальный `.gitignore` для:
|
||||
|
||||
```text
|
||||
/generated/
|
||||
/index.ts
|
||||
/manifest.ts
|
||||
```
|
||||
|
||||
Локальный `.gitignore` следует один раз добавить в репозиторий. Он исключает остальные generated-файлы, поэтому генерацию нужно запускать перед командами, которые импортируют sprite-модуль:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites",
|
||||
"pretypecheck": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
CI должен устанавливать development dependencies и выполнять generation script до сборки или проверки типов.
|
||||
|
||||
Если в каталоге спрайта уже находится пользовательский `.gitignore`, `index.ts` или `manifest.ts`, генератор не перезапишет его. Переместите пользовательский файл или выберите отдельный каталог спрайта.
|
||||
|
||||
## Диагностика
|
||||
|
||||
- Нет `index.ts`: запустите generation script до импорта модуля.
|
||||
- Не найдена конфигурация: проверьте путь CLI и имя `svg-sprite.config.ts`.
|
||||
- Иконка отсутствует в типе: проверьте `inputFiles`, расширение `.svg` и уровень вложенности `inputFolder`.
|
||||
- Конфликт имени: два разных SVG имеют одинаковый basename; переименуйте один файл.
|
||||
- `Refusing to overwrite a user file`: в managed-пути находится файл без generated marker.
|
||||
- Иконка не меняет цвет: используйте `<svg><use>` или generated-компонент и проверьте `replaceColors`.
|
||||
- Webpack выдаёт неверный URL: проверьте Asset Modules, `output.publicPath` и SVG loaders.
|
||||
- Viewer не видит спрайт: проверьте путь к `manifest.ts` и выполните генерацию до запуска приложения.
|
||||
- Build и mode не совпадают: используйте target, соответствующий фактическому сборщику.
|
||||
|
||||
Для собственного orchestration и низкоуровневой компиляции смотрите [Программный API](programmatic-api.md).
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@gromlab/svg-sprites",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@gromlab/svg-sprites",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"colorette": "^2.0.20",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@gromlab/svg-sprites",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.4",
|
||||
"description": "Generate SVG sprites and typed icon components for React and Next.js",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
@@ -65,11 +65,11 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gromov-sergei/svg-sprites"
|
||||
"url": "https://github.com/gromlab-ru/svg-sprites"
|
||||
},
|
||||
"homepage": "https://github.com/gromov-sergei/svg-sprites",
|
||||
"homepage": "https://github.com/gromlab-ru/svg-sprites",
|
||||
"bugs": {
|
||||
"url": "https://github.com/gromov-sergei/svg-sprites/issues"
|
||||
"url": "https://github.com/gromlab-ru/svg-sprites/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -96,7 +96,7 @@ export const App = () => {
|
||||
<span className={styles.footerText}>@gromlab/svg-sprites</span>
|
||||
<a
|
||||
className={styles.footerLink}
|
||||
href="https://github.com/gromov-sergei/svg-sprites"
|
||||
href="https://github.com/gromlab-ru/svg-sprites"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
||||
@@ -12,4 +12,4 @@ The package supports multiple independent sprites in one project. Each selected
|
||||
|
||||
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.
|
||||
|
||||
Generated production components do not import `@gromlab/svg-sprites` at runtime. For routine generation, run the latest CLI through `npx`; install the package in the project only when `SpriteViewer`, the programmatic API, or a local config helper is required.
|
||||
Generated production components do not import `@gromlab/svg-sprites` at runtime. Install the package as a development dependency so configuration helpers and the local CLI use the version recorded in the project's lockfile.
|
||||
|
||||
@@ -12,10 +12,14 @@ Select exactly one supported mode key:
|
||||
| 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. The CLI always requires a mode and exactly one path to a configuration directory:
|
||||
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:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode <mode-key> <sprite-directory>
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:<name>": "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.
|
||||
|
||||
@@ -12,18 +12,26 @@ src/ui/file-manager/svg-sprite/
|
||||
|
||||
One `svg-sprite.config.ts` creates one independent sprite. For multiple sets, choose multiple directories and assign each a unique `name`.
|
||||
|
||||
When running through `npx`, the config may export a plain object without importing the package:
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Use the configuration helper for autocomplete and type checking:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../shared/icons/close.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The object contract is the same for React and Next.js. If the package is already installed, the object may be wrapped in `defineReactSpriteConfig(...)` or `defineNextSpriteConfig(...)` for autocomplete. A helper is not required for normal CLI generation.
|
||||
The object contract is the same for React and Next.js. Use `defineNextSpriteConfig(...)` instead for a Next.js sprite.
|
||||
|
||||
`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.
|
||||
|
||||
@@ -32,7 +40,7 @@ Add a separate command with the selected mode key and one path:
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"sprites": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,4 +70,4 @@ Automatic replacement targets `fill`/`stroke` attributes and inline `style`. The
|
||||
- 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'`.
|
||||
|
||||
The Viewer accepts manifests/loaders and provides search, themes, colors, and examples, but production components do not depend on it. To import `@gromlab/svg-sprites/react`, install the package using the project's package manager.
|
||||
The Viewer accepts manifests/loaders and provides search, themes, colors, and examples, but production components do not depend on it. Import it from the package already installed as a development dependency.
|
||||
|
||||
@@ -5,7 +5,7 @@ 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.
|
||||
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.
|
||||
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` or `npx tsc --noEmit`.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -9,10 +9,10 @@ Use this document when a source contains `<defs>`, gradients, patterns, filters,
|
||||
Inspect the source SVG before editing it:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
Replace the mode and path with the actual values. 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 `generated/sprite.svg` and the manifest; do not draw conclusions from a successful exit code alone.
|
||||
|
||||
Pay particular attention to:
|
||||
|
||||
@@ -36,17 +36,19 @@ 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.
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'illustrations',
|
||||
transform: {
|
||||
removeSize: false,
|
||||
replaceColors: false,
|
||||
addTransition: false,
|
||||
},
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
This is a plain config for one of potentially many sprite directories in a project; its directory does not have to match a module/feature directory. Use the same `transform` for Next; in legacy mode it belongs at the top level of the config. When the package is installed locally for SpriteViewer or the programmatic API, the object may optionally be wrapped in the appropriate `define*Config(...)` helper.
|
||||
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(...)`.
|
||||
|
||||
## Dimensions and viewBox
|
||||
|
||||
|
||||
@@ -15,10 +15,18 @@ Use this document when the project already has a root `svg-sprites.config.ts`, c
|
||||
|
||||
## Config and execution
|
||||
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
`svg-sprites.config.ts`:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
transform: {
|
||||
@@ -41,28 +49,24 @@ export default {
|
||||
format: 'stack',
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The package does not need to be installed for normal CLI use. If it is installed locally for the programmatic API, the config may optionally be wrapped in `defineLegacyConfig(...)` for autocomplete. 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.
|
||||
|
||||
Run from the project root:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode legacy .
|
||||
```
|
||||
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": "npx --yes @gromlab/svg-sprites@latest --mode legacy .",
|
||||
"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
|
||||
@@ -116,7 +120,7 @@ Run a production build and browser/Network checks additionally only when the out
|
||||
## 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`: add plain `export default { ... }`; a locally installed helper is optional.
|
||||
- `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.
|
||||
|
||||
@@ -10,13 +10,12 @@ First record the project's current contract:
|
||||
|
||||
```bash
|
||||
npm ls @gromlab/svg-sprites
|
||||
npx --yes @gromlab/svg-sprites@latest --help
|
||||
```
|
||||
|
||||
If this is an actual migration of imports, config helpers, or the programmatic API, install the current package locally. Installation is unnecessary for CLI generation alone:
|
||||
Install the current package as a development dependency before updating the config and scripts:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Find and read:
|
||||
@@ -41,10 +40,12 @@ API mapping:
|
||||
| `sprites[].mode` | `sprites[].format` |
|
||||
| `generate` | `generateLegacy` |
|
||||
| `loadConfig` | `loadLegacyConfig` |
|
||||
| CLI without mode | `npx --yes @gromlab/svg-sprites@latest --mode legacy <config-dir>` |
|
||||
| CLI without mode | `svg-sprites --mode legacy <config-dir>` in a package script |
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
sprites: [
|
||||
@@ -54,12 +55,18 @@ export default {
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy ."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --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).
|
||||
|
||||
@@ -70,14 +77,16 @@ Choose this path when typed components, bundler-hashed assets, Server Components
|
||||
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
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'global',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
When the package is installed locally, the object may optionally be wrapped in `defineReactSpriteConfig(...)` or, for Next.js, `defineNextSpriteConfig(...)`. Then select exactly one mode:
|
||||
For Next.js, use `defineNextSpriteConfig(...)` instead. Then select exactly one mode:
|
||||
|
||||
| Environment | Mode |
|
||||
|---|---|
|
||||
@@ -90,10 +99,17 @@ When the package is installed locally, the object may optionally be wrapped in `
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/global/svg-sprite
|
||||
```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
|
||||
|
||||
@@ -6,12 +6,12 @@ Use this document when the application uses `app/` or `src/app/` and needs a gen
|
||||
|
||||
## Target matrix
|
||||
|
||||
| Bundler | CLI mode | Minimum Next.js version | Conditional verification build |
|
||||
|---|---|---:|---|
|
||||
| Turbopack | `next@app/turbopack` | 16.2 | `npx next build --turbopack` |
|
||||
| Webpack 5 | `next@app/webpack` | 13.4 | Next 13-15: `npx next build`; Next 16: `npx next build --webpack` |
|
||||
| Bundler | CLI mode |
|
||||
|---|---|
|
||||
| Turbopack | `next@app/turbopack` |
|
||||
| Webpack 5 | `next@app/webpack` |
|
||||
|
||||
Do not infer the target only from the presence of `next.config.*`. Check the installed Next.js version and the actual flags in `dev`/`build`. The generator mode and verification-build bundler must agree.
|
||||
Do not infer the target only from the presence of `next.config.*`. Check the actual flags in `dev`/`build`. The generator mode and verification-build bundler must agree.
|
||||
|
||||
## Prepare the sprite directory
|
||||
|
||||
@@ -23,16 +23,23 @@ src/ui/file-manager/svg-sprite/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- The package does not need to be installed for normal CLI generation. When installed locally for SpriteViewer or the programmatic API, the object may optionally be wrapped in `defineNextSpriteConfig(...)` for autocomplete.
|
||||
- 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`.
|
||||
- Paths are relative to its directory; `inputFolder` scanning is shallow.
|
||||
@@ -44,24 +51,12 @@ export default {
|
||||
|
||||
## Generation
|
||||
|
||||
For Turbopack:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@app/turbopack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
For Webpack 5:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@app/webpack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Example scripts for Turbopack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -69,7 +64,7 @@ Example scripts for Turbopack:
|
||||
}
|
||||
```
|
||||
|
||||
For Webpack, replace only the complete mode with `next@app/webpack`. Do not run both targets sequentially for one directory: the second generation overwrites the first target's files.
|
||||
For Webpack, replace only the complete mode with `next@app/webpack`. Do not run both targets sequentially for one directory: the second generation overwrites the first target's files. Run `npm run sprite:file-manager` for the first generation.
|
||||
|
||||
## Server Component
|
||||
|
||||
@@ -95,12 +90,6 @@ Do not import from `generated/` or move the SVG into `public`. Managed files (`g
|
||||
|
||||
The Viewer is interactive and imported from a client-only entry. Create a separate Client Component page or child component:
|
||||
|
||||
Install the package locally for the Viewer:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
@@ -124,23 +113,15 @@ Start with generation and typechecking:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
npx tsc --noEmit
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
If the target or Next build/deployment pipeline changed, or a runtime issue is being diagnosed, then run exactly one production build matching the target:
|
||||
If the target or Next build/deployment pipeline changed, or a runtime issue is being diagnosed, run the project's production build configured for the selected bundler:
|
||||
|
||||
```bash
|
||||
npx next build --turbopack
|
||||
npm run build
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```bash
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
For Webpack on Next 13-15, use `npx next build` without a flag.
|
||||
|
||||
After the required generation and typecheck, verify that:
|
||||
|
||||
- `manifest.ts` contains the exact target `next@app/turbopack` or `next@app/webpack`;
|
||||
@@ -157,7 +138,7 @@ During a conditional production/runtime check, also verify that:
|
||||
|
||||
- `Next.js mode requires a router and bundler`: `--mode next` is invalid; specify the full mode.
|
||||
- Build passes with one bundler but the runtime asset breaks with another: regenerate for the target actually used by the build.
|
||||
- Webpack was selected on Next 16, but the build used Turbopack: use `next build --webpack` 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.
|
||||
- `React config file not found`: the command received the path to `app/`, `icons/`, or the config file instead of the sprite directory.
|
||||
- Two CI jobs generate different targets in one checkout: separate their directories or ensure each job uses one consistent target.
|
||||
|
||||
@@ -6,12 +6,12 @@ Use this document for pages under `pages/` or `src/pages/`, including SSR with `
|
||||
|
||||
## Selecting a target
|
||||
|
||||
| Bundler | CLI mode | Minimum Next.js version | Conditional build check |
|
||||
|---|---|---:|---|
|
||||
| Turbopack | `next@pages/turbopack` | 16.2 | `npx next build --turbopack` |
|
||||
| Webpack 5 | `next@pages/webpack` | 12.2 | Next 12-15: `npx next build`; Next 16: `npx next build --webpack` |
|
||||
| Bundler | CLI mode |
|
||||
|---|---|
|
||||
| Turbopack | `next@pages/turbopack` |
|
||||
| Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
Next.js 12.2 requires React 18. Determine the installed version and the actual script flags before selecting a mode. The presence of the Pages Router does not automatically imply Webpack: Next 16.2 supports Turbopack.
|
||||
Determine the actual script flags before selecting a mode. The presence of the Pages Router does not automatically imply Webpack; select the target from the bundler used by the project.
|
||||
|
||||
## Structure and config
|
||||
|
||||
@@ -23,16 +23,24 @@ src/ui/file-manager/svg-sprite/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The package does not need to be installed for normal CLI generation. When installed locally for SpriteViewer or the programmatic API, the config may optionally be wrapped in `defineNextSpriteConfig(...)` for autocomplete. The project chooses the directory containing each specific sprite config, and it does not have to be a module/feature directory; each config describes one of potentially many application sprites.
|
||||
The project chooses the directory containing each specific sprite config, and it does not have to be a module/feature directory; each config describes one of potentially many application sprites.
|
||||
|
||||
All source paths are resolved from the config directory. `inputFolder` defaults to `./icons`, and scanning is shallow. `inputFiles` is merged with the folder. The same path is deduplicated, but two different `check.svg` files conflict. An explicitly configured missing folder is an error even when `inputFiles` is non-empty.
|
||||
|
||||
@@ -40,24 +48,12 @@ All source paths are resolved from the config directory. `inputFolder` defaults
|
||||
|
||||
## Commands
|
||||
|
||||
Webpack 5:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@pages/webpack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Turbopack:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@pages/turbopack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Example lifecycle scripts for Webpack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -65,7 +61,7 @@ Example lifecycle scripts for Webpack:
|
||||
}
|
||||
```
|
||||
|
||||
If pre-scripts already exist, add generation to their current command chain. Generated imports are absent from Git, so generation must precede TypeScript and Next compilation.
|
||||
If pre-scripts already exist, add generation to their current command chain. Generated imports are absent from Git, so generation must precede TypeScript and Next compilation. For Turbopack, replace the complete mode with `next@pages/turbopack`. Run `npm run sprite:file-manager` for the first generation.
|
||||
|
||||
## Usage in the Pages Router
|
||||
|
||||
@@ -89,12 +85,6 @@ Import the component and types only from the local `svg-sprite/index.ts`. Do not
|
||||
|
||||
Pages Router components run on the client as well, so a separate `'use client'` directive is unnecessary:
|
||||
|
||||
Install the package locally for SpriteViewer:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
@@ -114,23 +104,15 @@ Use literal imports and expose the page only as a debug/internal tool. If the pa
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
npx tsc --noEmit
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
If the target or Next build/deployment pipeline changed, or a runtime issue is being diagnosed, run a production build for the selected bundler:
|
||||
If the target or Next build/deployment pipeline changed, or a runtime issue is being diagnosed, run the project's production build configured for the selected bundler:
|
||||
|
||||
```bash
|
||||
npx next build --turbopack
|
||||
npm run build
|
||||
```
|
||||
|
||||
or, for Webpack on Next 16:
|
||||
|
||||
```bash
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
For Webpack on Next 12-15, run `npx next build`.
|
||||
|
||||
After the required generation and typecheck, verify that:
|
||||
|
||||
- `manifest.ts` contains `next@pages/turbopack` or `next@pages/webpack`;
|
||||
@@ -146,8 +128,7 @@ After the conditional production build, and only when browser tools are availabl
|
||||
## Common failures
|
||||
|
||||
- Mode uses `next@app/...`: the module may generate, but its manifest and target contract are wrong; use `next@pages/...`.
|
||||
- On Next 16, the command and mode select different bundlers: add the matching build flag and regenerate.
|
||||
- Next 12.2 uses React 17: upgrade React to 18 before diagnosing the sprite runtime.
|
||||
- The command and mode select different bundlers: use the project's matching build command and regenerate.
|
||||
- Viewer manifest is missing from the chunk: the `import()` path must be a string literal and must exist before the Next build.
|
||||
- Icon appears after a full reload but disappears during navigation: check external asset availability with `basePath`, `assetPrefix`, and the production origin.
|
||||
- `Refusing to overwrite a user file`: the sprite directory contains an unmanaged file with a reserved name; move it.
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
## Required installation
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Programmatic imports require a local dependency; `npx` does not replace it. This reference always describes the package's latest API.
|
||||
Programmatic imports require the local development dependency shown above. This reference describes the installed package API.
|
||||
|
||||
## When to use this reference
|
||||
|
||||
|
||||
@@ -23,18 +23,25 @@ src/ui/file-manager/svg-sprite/
|
||||
|
||||
## Setup
|
||||
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- The package does not need to be installed for normal CLI generation. If it is already installed locally for SpriteViewer or the programmatic API, `defineReactSpriteConfig(...)` may be used as an optional autocomplete helper.
|
||||
- Each config describes one specific sprite; an application may contain many independent configs and sprites.
|
||||
- Every config path is resolved relative to the directory containing `svg-sprite.config.ts`.
|
||||
- `inputFolder` defaults to `./icons`; folder scanning is shallow and includes files ending in `.svg`.
|
||||
@@ -46,18 +53,12 @@ export default {
|
||||
|
||||
## Command and scripts
|
||||
|
||||
Exact command for the example above:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Add it to `package.json` and run it before processes that need generated imports:
|
||||
Add the local CLI to `package.json` and run it before processes that need generated imports:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -67,6 +68,8 @@ Add it to `package.json` and run it before processes that need generated imports
|
||||
|
||||
If the project already has `predev` or `prebuild`, integrate generation into the existing orchestration instead of overwriting the script.
|
||||
|
||||
Run `npm run sprite:file-manager` for the first generation.
|
||||
|
||||
## Usage
|
||||
|
||||
Import only from the public local entry point:
|
||||
@@ -118,11 +121,7 @@ A manual `#check` fragment is safe only for names matching `^[a-zA-Z][a-zA-Z0-9_
|
||||
|
||||
## SpriteViewer
|
||||
|
||||
After generation, install the package if needed and add the Viewer only to a debug route:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
After generation, add the Viewer only to a debug route:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
@@ -23,31 +23,33 @@ src/ui/file-manager/svg-sprite/
|
||||
|
||||
## Configuration and generation
|
||||
|
||||
Install the package as a development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The package does not need to be installed for normal CLI generation. When installed locally for SpriteViewer or the programmatic API, the config may optionally be wrapped in `defineReactSpriteConfig(...)` for autocomplete. Each config describes one of potentially many independent application sprites.
|
||||
Each config describes one of potentially many independent application sprites.
|
||||
|
||||
Paths are relative to `svg-sprite.config.ts`. The folder is scanned only at its top level. `inputFolder` and `inputFiles` are merged; duplicate paths are deduplicated, but equal basenames from different files cause an ID conflict. The implicit `./icons` folder may be absent when `inputFiles` is non-empty; an explicitly configured missing folder is an error. `FileManagerIcon` below is only an example generated name for `name: 'file-manager'`.
|
||||
|
||||
Exact command:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@webpack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Recommended lifecycle hooks:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode react@webpack src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -55,7 +57,7 @@ Recommended lifecycle hooks:
|
||||
}
|
||||
```
|
||||
|
||||
Do not overwrite existing pre-scripts; add generation to their current command chain. The React preset always emits `stack`.
|
||||
Do not overwrite existing pre-scripts; add generation to their current command chain. Run `npm run sprite:file-manager` for the first generation. The React preset always emits `stack`.
|
||||
|
||||
## Public component
|
||||
|
||||
@@ -105,12 +107,6 @@ Integrate this rule with the project's current configuration; do not add a dupli
|
||||
|
||||
Webpack does not provide `import.meta.glob`. Pass static lazy imports with string-literal paths:
|
||||
|
||||
SpriteViewer requires the package to be installed locally:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
|
||||
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Имена `FileManagerIcon` и `fileManagerIconNames` ниже являются примерами API одного из возможных спрайтов, а не фиксированными экспортами пакета.
|
||||
|
||||
Generated production-компоненты не импортируют `@gromlab/svg-sprites` во время выполнения. Для обычной генерации запускай latest CLI через `npx`; устанавливай пакет в проект, только если нужен `SpriteViewer`, программный API или локальный config helper.
|
||||
Generated production-компоненты не импортируют `@gromlab/svg-sprites` во время выполнения. Устанавливай пакет как development dependency, чтобы config helpers и локальный CLI использовали версию из lockfile проекта.
|
||||
|
||||
@@ -12,10 +12,14 @@
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
| Старый общий конфиг | `legacy` |
|
||||
|
||||
Не используй неполные `react`, `next@app`, `next@pages`, будущий `standalone` или mode другого сборщика. CLI всегда требует mode и ровно один путь к каталогу конфигурации:
|
||||
Не используй неполные `react`, `next@app`, `next@pages`, будущий `standalone` или mode другого сборщика. Установи пакет как development dependency и добавь локальный CLI в package script. CLI всегда требует mode и ровно один путь к каталогу конфигурации:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode <mode-key> <sprite-directory>
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:<name>": "svg-sprites --mode <mode-key> <sprite-directory>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не передавай несколько путей, glob или путь к самому файлу конфигурации. Для нескольких современных спрайтов создай отдельную команду для каждого каталога.
|
||||
|
||||
@@ -12,18 +12,26 @@ src/ui/file-manager/svg-sprite/
|
||||
|
||||
Один `svg-sprite.config.ts` создаёт один независимый спрайт. Для нескольких наборов выбери несколько каталогов и дай каждому уникальное `name`.
|
||||
|
||||
Для запуска через `npx` конфиг может экспортировать обычный объект без импорта пакета:
|
||||
Установи пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Используй config helper для autocomplete и проверки типов:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../shared/icons/close.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Контракт объекта одинаков для React и Next.js. Если пакет уже установлен, объект можно обернуть в `defineReactSpriteConfig(...)` или `defineNextSpriteConfig(...)` ради autocomplete. Для обычной CLI-генерации helper не обязателен.
|
||||
Контракт объекта одинаков для React и Next.js. Для Next.js-спрайта используй `defineNextSpriteConfig(...)`.
|
||||
|
||||
`name` должен начинаться с латинской буквы и записываться в kebab-case; из примера `file-manager` будут созданы `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`. Другой спрайт получает собственные имена. Если `name` не задан, генератор выводит его из каталога.
|
||||
|
||||
@@ -32,7 +40,7 @@ export default {
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"sprites": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,4 +70,4 @@ Generated-компонент не выбирает семантику за пр
|
||||
- в Webpack передай массив статических `() => import('.../manifest')`;
|
||||
- в Next.js используй такие же статические loaders, а для App Router помести Viewer в отдельный файл с `'use client'`.
|
||||
|
||||
Viewer принимает manifests/loaders, показывает поиск, темы, цвета и примеры, но production-компоненты от него не зависят. Чтобы импортировать `@gromlab/svg-sprites/react`, установи пакет в проект подходящим для его package manager способом.
|
||||
Viewer принимает manifests/loaders, показывает поиск, темы, цвета и примеры, но production-компоненты от него не зависят. Импортируй его из пакета, уже установленного как development dependency.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
1. Запусти точную sprite-команду, например `npm run sprite:file-manager`; процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `generated`.
|
||||
2. Проверь наличие `index.ts`, `manifest.ts`, `generated/sprite.svg`, `generated/react-component.tsx`, `generated/types.ts`, `generated/styles.module.css` и `generated/.svg-sprites.manifest.json`.
|
||||
3. Убедись, что новая иконка присутствует в readonly-массиве имён и принимается prop `icon`.
|
||||
4. Запусти существующую проверку типов проекта, например `npm run typecheck` или `npx tsc --noEmit`.
|
||||
4. Запусти существующую проверку типов проекта, например `npm run typecheck`.
|
||||
5. Проверь в `manifest.ts`, что `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.
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
Проверь исходный SVG до редактирования:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
Замени mode и path на фактические. Затем сравни source с `generated/sprite.svg` и manifest, не делая вывод только по успешному exit code.
|
||||
Используй фактический package script нужного спрайта. Затем сравни source с `generated/sprite.svg` и manifest, не делая вывод только по успешному exit code.
|
||||
|
||||
Особого внимания требуют:
|
||||
|
||||
@@ -36,17 +36,19 @@ npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-
|
||||
Все три опции по умолчанию `true` и применяются ко всему спрайту, не к отдельной иконке.
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'illustrations',
|
||||
transform: {
|
||||
removeSize: false,
|
||||
replaceColors: false,
|
||||
addTransition: false,
|
||||
},
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Это plain config для одного из потенциально многих проектов спрайтов; его каталог не обязан совпадать с module/feature-каталогом. Для Next используй тот же `transform`; для legacy он находится на верхнем уровне config. При локальной установке пакета ради SpriteViewer или программного API объект можно опционально обернуть в подходящий `define*Config(...)` helper.
|
||||
Это config для одного из потенциально многих проектов спрайтов; его каталог не обязан совпадать с module/feature-каталогом. Для Next используй `defineNextSpriteConfig(...)` с тем же `transform`; для legacy он находится на верхнем уровне `defineLegacyConfig(...)`.
|
||||
|
||||
## Размеры и viewBox
|
||||
|
||||
|
||||
@@ -15,10 +15,18 @@
|
||||
|
||||
## Конфиг и запуск
|
||||
|
||||
Установи пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
`svg-sprites.config.ts`:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
transform: {
|
||||
@@ -41,28 +49,24 @@ export default {
|
||||
format: 'stack',
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Для обычного CLI пакет устанавливать не нужно. Если он установлен локально ради программного API, config можно опционально обернуть в `defineLegacyConfig(...)` для autocomplete. В отличие от локальных React/Next config, каждый из которых описывает один из потенциально многих спрайтов, один legacy config сохраняет специфическую возможность управлять одним или несколькими entries спрайтов.
|
||||
|
||||
Запуск из project root:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode legacy .
|
||||
```
|
||||
В отличие от локальных React/Next config, каждый из которых описывает один из потенциально многих спрайтов, один legacy config сохраняет специфическую возможность управлять одним или несколькими entries спрайтов.
|
||||
|
||||
Script:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes @gromlab/svg-sprites@latest --mode legacy .",
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Запусти `npm run sprites` из project root.
|
||||
|
||||
CLI path указывает каталог с `svg-sprites.config.ts`. Не передавай сам файл. Для config в другом каталоге передай этот каталог явно.
|
||||
|
||||
## Семантика input
|
||||
@@ -116,7 +120,7 @@ Production build и браузер/Network запускай дополнител
|
||||
## Типовые ошибки
|
||||
|
||||
- `Config file not found`: CLI path не является каталогом с `svg-sprites.config.ts`.
|
||||
- `Config file must have a default export`: добавь plain `export default { ... }`; локально установленный helper здесь необязателен.
|
||||
- `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.
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
|
||||
```bash
|
||||
npm ls @gromlab/svg-sprites
|
||||
npx --yes @gromlab/svg-sprites@latest --help
|
||||
```
|
||||
|
||||
Если это реальная миграция импортов, config helpers или программного API, установи актуальный пакет локально. Для одной только CLI-генерации установка не нужна:
|
||||
Перед обновлением config и scripts установи актуальный пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Найди и прочитай:
|
||||
@@ -41,10 +40,12 @@ npm install @gromlab/svg-sprites@latest
|
||||
| `sprites[].mode` | `sprites[].format` |
|
||||
| `generate` | `generateLegacy` |
|
||||
| `loadConfig` | `loadLegacyConfig` |
|
||||
| CLI без mode | `npx --yes @gromlab/svg-sprites@latest --mode legacy <config-dir>` |
|
||||
| CLI без mode | `svg-sprites --mode legacy <config-dir>` в package script |
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
sprites: [
|
||||
@@ -54,12 +55,18 @@ export default {
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy ."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode legacy .
|
||||
```
|
||||
Запусти его командой `npm run sprites`.
|
||||
|
||||
`publicPath` и генерация старого общего React-компонента удалены. Если приложение использовало этот компонент, legacy сохранит SVG asset, но React wrapper придётся заменить отдельно. Полный legacy workflow находится в [legacy.md](legacy.md).
|
||||
|
||||
@@ -70,14 +77,16 @@ npx --yes @gromlab/svg-sprites@latest --mode legacy .
|
||||
Для каждого нужного спрайта создай каталог проекта с локальным `svg-sprite.config.ts` и, при использовании папки, `icons/`. Каталог не обязан быть module/feature-каталогом; каждый config описывает один из потенциально многих спрайтов:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'global',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
При локальной установке package объект можно опционально обернуть в `defineReactSpriteConfig(...)` или, для Next.js, `defineNextSpriteConfig(...)`. Затем выбери ровно один mode:
|
||||
Для Next.js используй `defineNextSpriteConfig(...)`. Затем выбери ровно один mode:
|
||||
|
||||
| Среда | Mode |
|
||||
|---|---|
|
||||
@@ -90,10 +99,17 @@ export default {
|
||||
|
||||
Пример:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/global/svg-sprite
|
||||
```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
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
## Матрица target
|
||||
|
||||
| Сборщик | CLI mode | Минимальная версия Next.js | Команда условной контрольной сборки |
|
||||
|---|---|---:|---|
|
||||
| Turbopack | `next@app/turbopack` | 16.2 | `npx next build --turbopack` |
|
||||
| Webpack 5 | `next@app/webpack` | 13.4 | Next 13-15: `npx next build`; Next 16: `npx next build --webpack` |
|
||||
| Сборщик | CLI mode |
|
||||
|---|---|
|
||||
| Turbopack | `next@app/turbopack` |
|
||||
| Webpack 5 | `next@app/webpack` |
|
||||
|
||||
Не выводи target только из наличия `next.config.*`. Проверь установленную версию Next.js и фактические flags в `dev`/`build`. Mode генератора и сборщик контрольной сборки должны совпадать.
|
||||
Не выводи target только из наличия `next.config.*`. Проверь фактические flags в `dev`/`build`. Mode генератора и сборщик контрольной сборки должны совпадать.
|
||||
|
||||
## Подготовка каталога спрайта
|
||||
|
||||
@@ -23,16 +23,23 @@ src/ui/file-manager/svg-sprite/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Установи пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- Для обычной CLI-генерации пакет устанавливать не нужно. При локальной установке ради SpriteViewer или программного API объект можно опционально обернуть в `defineNextSpriteConfig(...)` для autocomplete.
|
||||
- Каталог выбирает проект конкретного спрайта и не обязан быть module/feature-каталогом. Каждый config описывает один из потенциально многих спрайтов приложения.
|
||||
- Конфиг называется в единственном числе: `svg-sprite.config.ts`.
|
||||
- Пути считаются от его каталога; `inputFolder` сканируется нерекурсивно.
|
||||
@@ -44,24 +51,12 @@ export default {
|
||||
|
||||
## Генерация
|
||||
|
||||
Для Turbopack:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@app/turbopack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Для Webpack 5:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@app/webpack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Пример scripts для Turbopack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -69,7 +64,7 @@ npx --yes @gromlab/svg-sprites@latest --mode next@app/webpack src/ui/file-manage
|
||||
}
|
||||
```
|
||||
|
||||
Для Webpack замени только mode целиком на `next@app/webpack`. Не запускай два target последовательно для одного каталога: второй перезапишет generated target первого.
|
||||
Для Webpack замени только mode целиком на `next@app/webpack`. Не запускай два target последовательно для одного каталога: второй перезапишет generated target первого. Для первой генерации запусти `npm run sprite:file-manager`.
|
||||
|
||||
## Server Component
|
||||
|
||||
@@ -95,12 +90,6 @@ export default function Page() {
|
||||
|
||||
Viewer интерактивен и импортируется из client-only entry. Создай отдельную Client Component страницу или дочерний компонент:
|
||||
|
||||
Для Viewer установи пакет локально:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
@@ -124,23 +113,15 @@ export default function SpritesPage() {
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
npx tsc --noEmit
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
Если менялись target или Next build/deployment pipeline либо диагностируется runtime, затем запусти ровно одну production-сборку, соответствующую target:
|
||||
Если менялись target или Next build/deployment pipeline либо диагностируется runtime, запусти production-сборку проекта, настроенную на выбранный сборщик:
|
||||
|
||||
```bash
|
||||
npx next build --turbopack
|
||||
npm run build
|
||||
```
|
||||
|
||||
или:
|
||||
|
||||
```bash
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
Для Next 13-15 Webpack используй `npx next build` без flag.
|
||||
|
||||
После обязательных генерации и typecheck проверь:
|
||||
|
||||
- `manifest.ts` содержит точный target `next@app/turbopack` либо `next@app/webpack`;
|
||||
@@ -157,7 +138,7 @@ npx next build --webpack
|
||||
|
||||
- `Next.js mode requires a router and bundler`: нельзя использовать `--mode next`; укажи полный mode.
|
||||
- Сборка проходит на одном bundler, а runtime asset ломается на другом: перегенерируй тем target, которым реально выполняется build.
|
||||
- В Next 16 выбран Webpack, но build ушёл в Turbopack: используй `next build --webpack` и `next@app/webpack`.
|
||||
- Выбран Webpack, но build ушёл в Turbopack: используй Webpack-команду проекта и `next@app/webpack`.
|
||||
- Viewer вызывает ошибку Server Component: файл с Viewer должен иметь `'use client'`; generated icon component этого не требует.
|
||||
- `React config file not found`: команда получила путь к `app/`, `icons/` или конфигу вместо каталога спрайта.
|
||||
- Две CI jobs генерируют разные target в одном checkout: раздели каталоги или обеспечь один согласованный target на job.
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
## Выбор target
|
||||
|
||||
| Сборщик | CLI mode | Минимальная версия Next.js | Условная проверка build |
|
||||
|---|---|---:|---|
|
||||
| Turbopack | `next@pages/turbopack` | 16.2 | `npx next build --turbopack` |
|
||||
| Webpack 5 | `next@pages/webpack` | 12.2 | Next 12-15: `npx next build`; Next 16: `npx next build --webpack` |
|
||||
| Сборщик | CLI mode |
|
||||
|---|---|
|
||||
| Turbopack | `next@pages/turbopack` |
|
||||
| Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
Для Next.js 12.2 требуется React 18. Определи установленную версию и реальные flags scripts до выбора mode. Наличие Pages Router не означает автоматически Webpack: в Next 16.2 поддерживается Turbopack.
|
||||
Определи реальные flags scripts до выбора mode. Наличие Pages Router не означает автоматически Webpack: выбирай target по сборщику проекта.
|
||||
|
||||
## Структура и конфиг
|
||||
|
||||
@@ -23,16 +23,24 @@ src/ui/file-manager/svg-sprite/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Установи пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Для обычной CLI-генерации пакет устанавливать не нужно. При локальной установке ради SpriteViewer или программного API config можно опционально обернуть в `defineNextSpriteConfig(...)` для autocomplete. Каталог с config выбирает проект конкретного спрайта и не обязан быть module/feature-каталогом; каждый config описывает один из потенциально многих спрайтов приложения.
|
||||
Каталог с config выбирает проект конкретного спрайта и не обязан быть module/feature-каталогом; каждый config описывает один из потенциально многих спрайтов приложения.
|
||||
|
||||
Все source paths разрешаются от каталога конфига. `inputFolder` по умолчанию `./icons`, сканирование не рекурсивно. `inputFiles` объединяется с папкой. Один и тот же путь дедуплицируется, но два разных `check.svg` конфликтуют. Явная отсутствующая папка считается ошибкой даже при заполненном `inputFiles`.
|
||||
|
||||
@@ -40,24 +48,12 @@ export default {
|
||||
|
||||
## Команды
|
||||
|
||||
Webpack 5:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@pages/webpack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Turbopack:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode next@pages/turbopack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Пример lifecycle для Webpack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -65,7 +61,7 @@ npx --yes @gromlab/svg-sprites@latest --mode next@pages/turbopack src/ui/file-ma
|
||||
}
|
||||
```
|
||||
|
||||
Если pre-scripts уже существуют, добавь генерацию в текущую цепочку. Generated imports отсутствуют в Git, поэтому генерация должна предшествовать TypeScript и Next compilation.
|
||||
Если pre-scripts уже существуют, добавь генерацию в текущую цепочку. Generated imports отсутствуют в Git, поэтому генерация должна предшествовать TypeScript и Next compilation. Для Turbopack замени mode целиком на `next@pages/turbopack`. Для первой генерации запусти `npm run sprite:file-manager`.
|
||||
|
||||
## Использование в Pages Router
|
||||
|
||||
@@ -89,12 +85,6 @@ export function getServerSideProps() {
|
||||
|
||||
Pages Router компоненты выполняются и на клиенте, поэтому отдельная директива `'use client'` не нужна:
|
||||
|
||||
Для SpriteViewer установи пакет локально:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
@@ -114,23 +104,15 @@ export default function SpritesPage() {
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
npx tsc --noEmit
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
Если менялись target или Next build/deployment pipeline либо диагностируется runtime, запусти production build для выбранного bundler:
|
||||
Если менялись target или Next build/deployment pipeline либо диагностируется runtime, запусти production build проекта, настроенный на выбранный сборщик:
|
||||
|
||||
```bash
|
||||
npx next build --turbopack
|
||||
npm run build
|
||||
```
|
||||
|
||||
или для Next 16 Webpack:
|
||||
|
||||
```bash
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
В Next 12-15 Webpack запускай `npx next build`.
|
||||
|
||||
После обязательных генерации и typecheck проверь:
|
||||
|
||||
- `manifest.ts` содержит `next@pages/turbopack` либо `next@pages/webpack`;
|
||||
@@ -146,8 +128,7 @@ npx next build --webpack
|
||||
## Типовые ошибки
|
||||
|
||||
- В mode указан `next@app/...`: модуль может сгенерироваться, но manifest и контракт target неверны; используй `next@pages/...`.
|
||||
- В Next 16 command и mode выбирают разные bundler: добавь соответствующий build flag и перегенерируй.
|
||||
- На Next 12.2 используется React 17: обнови React до 18 прежде, чем диагностировать sprite runtime.
|
||||
- Command и mode выбирают разные bundler: используй соответствующую build-команду проекта и перегенерируй.
|
||||
- Viewer manifest не попадает в chunk: путь `import()` должен быть строковым литералом и существовать до Next build.
|
||||
- Иконка есть после full reload, но пропадает при переходе: проверь доступность внешнего asset с `basePath`, `assetPrefix` и production origin.
|
||||
- `Refusing to overwrite a user file`: sprite-каталог содержит неуправляемый файл с зарезервированным именем; перенеси его.
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
## Обязательная установка
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Программные imports требуют локальной dependency: `npx` их не заменяет. Этот reference всегда относится к latest API пакета.
|
||||
Программные imports требуют локальной development dependency, установленной выше. Этот reference описывает API установленной версии пакета.
|
||||
|
||||
## Когда открывать
|
||||
|
||||
|
||||
@@ -23,18 +23,25 @@ src/ui/file-manager/svg-sprite/
|
||||
|
||||
## Настройка
|
||||
|
||||
Установи пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- Для обычной CLI-генерации пакет устанавливать не нужно. Если он уже установлен локально ради SpriteViewer или программного API, `defineReactSpriteConfig(...)` можно использовать как необязательный helper для autocomplete.
|
||||
- Каждый такой config описывает один конкретный спрайт; в приложении может быть много независимых config и спрайтов.
|
||||
- Все пути в конфиге разрешаются относительно каталога `svg-sprite.config.ts`.
|
||||
- `inputFolder` по умолчанию равен `./icons`; сканирование папки не рекурсивно и включает файлы с окончанием `.svg`.
|
||||
@@ -46,18 +53,12 @@ export default {
|
||||
|
||||
## Команда и scripts
|
||||
|
||||
Точная команда для примера выше:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Закрепи её в `package.json` и запускай до процессов, которым нужны generated imports:
|
||||
Добавь локальный CLI в `package.json` и запускай до процессов, которым нужны generated imports:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -67,6 +68,8 @@ npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-
|
||||
|
||||
Если в проекте уже есть `predev` или `prebuild`, объедини команды в существующем orchestration вместо перезаписи script.
|
||||
|
||||
Для первой генерации запусти `npm run sprite:file-manager`.
|
||||
|
||||
## Использование
|
||||
|
||||
Импортируй только публичный локальный entry:
|
||||
@@ -118,11 +121,7 @@ import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
||||
|
||||
## SpriteViewer
|
||||
|
||||
После генерации при необходимости установи пакет и добавь Viewer только на debug-маршрут:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
После генерации добавь Viewer только на debug-маршрут:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
@@ -23,31 +23,33 @@ src/ui/file-manager/svg-sprite/
|
||||
|
||||
## Конфигурация и генерация
|
||||
|
||||
Установи пакет как development dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
```ts
|
||||
export default {
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: ['../../../../shared/icons/check.svg'],
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Для обычной CLI-генерации пакет устанавливать не нужно. При локальной установке ради SpriteViewer или программного API config можно опционально обернуть в `defineReactSpriteConfig(...)` для autocomplete. Каждый config описывает один из потенциально многих независимых спрайтов приложения.
|
||||
Каждый config описывает один из потенциально многих независимых спрайтов приложения.
|
||||
|
||||
Пути считаются от `svg-sprite.config.ts`. Папка сканируется только на первом уровне. `inputFolder` и `inputFiles` объединяются; одинаковый путь дедуплицируется, но одинаковые basename у разных файлов вызывают конфликт ID. Неявный `./icons` можно не создавать, если заполнен `inputFiles`; явно заданная отсутствующая папка является ошибкой. `FileManagerIcon` ниже — только пример generated-имени из `name: 'file-manager'`.
|
||||
|
||||
Точная команда:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites@latest --mode react@webpack src/ui/file-manager/svg-sprite
|
||||
```
|
||||
|
||||
Рекомендуемые lifecycle hooks:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --mode react@webpack src/ui/file-manager/svg-sprite",
|
||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
@@ -55,7 +57,7 @@ npx --yes @gromlab/svg-sprites@latest --mode react@webpack src/ui/file-manager/s
|
||||
}
|
||||
```
|
||||
|
||||
Не затирай уже существующие pre-scripts: включи генерацию в их текущую цепочку. React preset всегда выпускает `stack`.
|
||||
Не затирай уже существующие pre-scripts: включи генерацию в их текущую цепочку. Для первой генерации запусти `npm run sprite:file-manager`. React preset всегда выпускает `stack`.
|
||||
|
||||
## Публичный компонент
|
||||
|
||||
@@ -105,12 +107,6 @@ Webpack 5 распознаёт его как Asset Module и заменяет н
|
||||
|
||||
Webpack не предоставляет `import.meta.glob`. Передай статические lazy imports со строковыми литералами:
|
||||
|
||||
Для SpriteViewer пакет должен быть установлен локально:
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites@latest
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const GENERATED_NOTICE = [
|
||||
'## Для изменений перегенерируйте SVG-спрайт. ##',
|
||||
'## ##',
|
||||
'## Генератор: @gromlab/svg-sprites ##',
|
||||
'## Репозиторий: https://github.com/gromov-sergei/svg-sprites ##',
|
||||
'## Репозиторий: https://github.com/gromlab-ru/svg-sprites ##',
|
||||
'----------------------------------------------------------------------',
|
||||
]
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ export function SpriteViewer({
|
||||
|
||||
<footer className="gromlab-sprite-viewer__footer">
|
||||
<span>@gromlab/svg-sprites</span>
|
||||
<a href="https://github.com/gromov-sergei/svg-sprites" target="_blank" rel="noreferrer">Repository</a>
|
||||
<a href="https://github.com/gromlab-ru/svg-sprites" target="_blank" rel="noreferrer">Repository</a>
|
||||
</footer>
|
||||
|
||||
{selected && (
|
||||
|
||||
Reference in New Issue
Block a user