mirror of
https://github.com/gromlab-ru/svg-sprites.git
synced 2026-07-22 04:40:17 +03:00
- добавлены синхронные английские и русские инструкции для агентов - расширена сборка документов из Markdown-фрагментов - артефакты перенесены в игнорируемый release output - обновлены README и проверки скиллов
167 lines
9.5 KiB
Markdown
167 lines
9.5 KiB
Markdown
# React с Vite: операционный reference
|
||
|
||
## Когда открывать
|
||
|
||
Открывай этот документ, если проект использует React без Next.js и собирается Vite, либо если generated-компонент содержит импорт `sprite.svg?no-inline`. Не применяй этот target к Webpack: для него открой [react-webpack.md](react-webpack.md).
|
||
|
||
## Сначала установи контекст
|
||
|
||
1. Проверь `package.json`: должны быть React, Vite и фактические команды `dev`, `build`, `typecheck`.
|
||
2. Найди существующие `svg-sprite.config.ts` и scripts с `svg-sprites`. Не создавай второй каталог для уже существующего спрайта.
|
||
3. Выбери целевой каталог для конкретного спрайта. Это не обязан быть каталог module или feature: генератор принимает каталог с config, а не путь к самому config или `icons/`.
|
||
4. Не редактируй вручную `generated/`, `index.ts`, `manifest.ts` и локальный `.gitignore`: ими владеет генератор.
|
||
|
||
Минимальная структура:
|
||
|
||
```text
|
||
src/ui/file-manager/svg-sprite/
|
||
├── icons/
|
||
│ ├── check.svg
|
||
│ └── folder.svg
|
||
└── svg-sprite.config.ts
|
||
```
|
||
|
||
## Настройка
|
||
|
||
`src/ui/file-manager/svg-sprite/svg-sprite.config.ts`:
|
||
|
||
```ts
|
||
export default {
|
||
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`.
|
||
- `inputFolder` и `inputFiles` объединяются, одинаковый абсолютный путь дедуплицируется.
|
||
- Если `inputFiles` заполнен, а неявного `./icons` нет, генерация работает только по списку. Явно заданная отсутствующая `inputFolder` всегда является ошибкой.
|
||
- Разные файлы с одинаковым basename, например два `check.svg`, конфликтуют как одно публичное имя иконки.
|
||
- `name` должен быть kebab-case и начинаться с латинской буквы. `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames` ниже — только пример generated-имён для `name: 'file-manager'`.
|
||
- React preset всегда создаёт формат `stack`; выбрать `symbol` здесь нельзя.
|
||
|
||
## Команда и scripts
|
||
|
||
Точная команда для примера выше:
|
||
|
||
```bash
|
||
npx --yes @gromlab/svg-sprites@latest --mode react@vite src/ui/file-manager/svg-sprite
|
||
```
|
||
|
||
Закрепи её в `package.json` и запускай до процессов, которым нужны generated imports:
|
||
|
||
```json
|
||
{
|
||
"scripts": {
|
||
"sprite:file-manager": "npx --yes @gromlab/svg-sprites@latest --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"
|
||
}
|
||
}
|
||
```
|
||
|
||
Если в проекте уже есть `predev` или `prebuild`, объедини команды в существующем orchestration вместо перезаписи script.
|
||
|
||
## Использование
|
||
|
||
Импортируй только публичный локальный entry:
|
||
|
||
```tsx
|
||
import { FileManagerIcon, fileManagerIconNames } from './svg-sprite'
|
||
import type { FileManagerIconName, FileManagerIconStyle } from './svg-sprite'
|
||
|
||
const colorStyle: FileManagerIconStyle = {
|
||
'--icon-color-1': '#2563eb',
|
||
}
|
||
|
||
export function FolderIcon({ icon }: { icon: FileManagerIconName }) {
|
||
return <FileManagerIcon icon={icon} className="icon" style={colorStyle} />
|
||
}
|
||
|
||
export const availableIcons = fileManagerIconNames
|
||
```
|
||
|
||
`width` и `height` в JSX необязательны: размер можно задать CSS-классом. Без `wrapped` компонент рендерит `<svg>` и принимает SVG attributes. С `wrapped={true}` корнем становится `<span>`, а внутренний SVG занимает его ширину и высоту:
|
||
|
||
```tsx
|
||
<FileManagerIcon icon="folder" wrapped className="iconBox" />
|
||
```
|
||
|
||
Не делай deep import из `generated/`: структура generated-файлов не является точкой интеграции.
|
||
|
||
## Нюанс target
|
||
|
||
Vite target генерирует статический импорт:
|
||
|
||
```ts
|
||
import spriteUrl from './sprite.svg?no-inline'
|
||
```
|
||
|
||
Query `?no-inline` обязателен: он не даёт Vite превратить небольшой SVG в data URL. Не удаляй query и не копируй generated SVG в `public`; Vite должен выпустить отдельный asset с content hash.
|
||
|
||
Для низкоуровневого `<use>` применяй тот же механизм:
|
||
|
||
```tsx
|
||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
||
|
||
<svg className="icon">
|
||
<use href={`${spriteUrl}#check`} />
|
||
</svg>
|
||
```
|
||
|
||
Ручной fragment `#check` безопасен только для имён вида `^[a-zA-Z][a-zA-Z0-9_-]*$`. Для пробелов и других символов generated-компонент использует стабильный hash ID; точный ID находится в `manifest.ts`.
|
||
|
||
## SpriteViewer
|
||
|
||
После генерации при необходимости установи пакет и добавь Viewer только на debug-маршрут:
|
||
|
||
```bash
|
||
npm install @gromlab/svg-sprites@latest
|
||
```
|
||
|
||
```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 function IconsDebugPage() {
|
||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||
}
|
||
```
|
||
|
||
Аргумент `import.meta.glob` должен оставаться строковым литералом. Генерация обязана завершиться до старта Vite, иначе новые `manifest.ts` не попадут в glob.
|
||
|
||
## Проверка результата
|
||
|
||
```bash
|
||
npm run sprite:file-manager
|
||
npm run typecheck
|
||
```
|
||
|
||
Это быстрые обязательные проверки. Проверь generated-файлы статически:
|
||
|
||
- публичный `index.ts` экспортирует компонент, props, style, union имени и runtime-массив;
|
||
- `manifest.ts` содержит `target: "vite"`, `format: "stack"` и ожидаемое число иконок;
|
||
|
||
Если менялись target, asset pipeline или диагностируется runtime, дополнительно запусти production build. При наличии браузерных инструментов проверь Network: отдельный `.svg` asset вместо `data:image/svg+xml`, успешный URL и `<use href="...svg#...">`. Для сложных цветов, `defs` и размеров следуй [complex-svg.md](complex-svg.md), не утверждая визуальный или a11y результат без доступных инструментов.
|
||
|
||
## Типовые ошибки
|
||
|
||
- `React config file not found`: в команду передан путь к `icons/` или к файлу; передай каталог, содержащий `svg-sprite.config.ts`.
|
||
- `React mode requires a target`: использован `--mode react`; нужен ровно `react@vite`.
|
||
- Иконки нет в autocomplete: проверь case-sensitive окончание `.svg`, нерекурсивное расположение и повторно запусти генерацию до typecheck.
|
||
- `Refusing to overwrite a user file`: не удаляй marker и не обходи writer; перенеси пользовательский файл или выбери другой sprite-каталог.
|
||
- Viewer пуст: проверь строковый glob, существование generated `manifest.ts` и порядок запуска `predev`.
|
||
- SVG оказался inline: проверь, что модуль сгенерирован target `vite` и импорт сохранил `?no-inline`.
|
||
- TypeScript не разрешает package subpath: используй TypeScript 5+ и `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||
|
||
Для запуска без CLI используй [programmatic-api.md](programmatic-api.md).
|