mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-28 10:12:11 +00:00
Revert "[feat] improve custom icon build script with TypeScript and error handling (#5202)"
This reverts commit 7d6e252814.
This commit is contained in:
@@ -265,7 +265,7 @@ The project supports three types of icons, all with automatic imports (no manual
|
|||||||
2. **Iconify Icons** - 200,000+ icons from various libraries: `<i-lucide:settings />`, `<i-mdi:folder />`
|
2. **Iconify Icons** - 200,000+ icons from various libraries: `<i-lucide:settings />`, `<i-mdi:folder />`
|
||||||
3. **Custom Icons** - Your own SVG icons: `<i-comfy:workflow />`
|
3. **Custom Icons** - Your own SVG icons: `<i-comfy:workflow />`
|
||||||
|
|
||||||
Icons are powered by the unplugin-icons system, which automatically discovers and imports icons as Vue components. Custom icons are stored in `src/assets/icons/custom/` and processed by `build/customIconCollection.ts` with automatic validation.
|
Icons are powered by the unplugin-icons system, which automatically discovers and imports icons as Vue components. Custom icons are stored in `src/assets/icons/custom/`.
|
||||||
|
|
||||||
For detailed instructions and code examples, see [src/assets/icons/README.md](src/assets/icons/README.md).
|
For detailed instructions and code examples, see [src/assets/icons/README.md](src/assets/icons/README.md).
|
||||||
|
|
||||||
|
|||||||
29
build/customIconCollection.js
Normal file
29
build/customIconCollection.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { readFileSync, readdirSync } from 'fs'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { dirname } from 'path'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
const fileName = fileURLToPath(import.meta.url)
|
||||||
|
const dirName = dirname(fileName)
|
||||||
|
const customIconsPath = join(dirName, '..', 'src', 'assets', 'icons', 'custom')
|
||||||
|
|
||||||
|
// Create an Iconify collection for custom icons
|
||||||
|
export const iconCollection = {
|
||||||
|
prefix: 'comfy',
|
||||||
|
icons: {},
|
||||||
|
width: 16,
|
||||||
|
height: 16
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all SVG files from the custom icons directory
|
||||||
|
const files = readdirSync(customIconsPath)
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (file.endsWith('.svg')) {
|
||||||
|
const name = file.replace('.svg', '')
|
||||||
|
const content = readFileSync(join(customIconsPath, file), 'utf-8')
|
||||||
|
|
||||||
|
iconCollection.icons[name] = {
|
||||||
|
body: content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
import { existsSync, readFileSync, readdirSync } from 'fs'
|
|
||||||
import { join } from 'path'
|
|
||||||
import { dirname } from 'path'
|
|
||||||
import { fileURLToPath } from 'url'
|
|
||||||
|
|
||||||
const fileName = fileURLToPath(import.meta.url)
|
|
||||||
const dirName = dirname(fileName)
|
|
||||||
const customIconsPath = join(dirName, '..', 'src', 'assets', 'icons', 'custom')
|
|
||||||
|
|
||||||
// Iconify collection structure
|
|
||||||
interface IconifyIcon {
|
|
||||||
body: string
|
|
||||||
width?: number
|
|
||||||
height?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IconifyCollection {
|
|
||||||
prefix: string
|
|
||||||
icons: Record<string, IconifyIcon>
|
|
||||||
width?: number
|
|
||||||
height?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an Iconify collection for custom icons
|
|
||||||
export const iconCollection: IconifyCollection = {
|
|
||||||
prefix: 'comfy',
|
|
||||||
icons: {},
|
|
||||||
width: 16,
|
|
||||||
height: 16
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates that an SVG file contains valid SVG content
|
|
||||||
*/
|
|
||||||
function validateSvgContent(content: string, filename: string): void {
|
|
||||||
if (!content.trim()) {
|
|
||||||
throw new Error(`Empty SVG file: ${filename}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!content.includes('<svg')) {
|
|
||||||
throw new Error(`Invalid SVG file (missing <svg> tag): ${filename}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic XML structure validation
|
|
||||||
const openTags = (content.match(/<svg[^>]*>/g) || []).length
|
|
||||||
const closeTags = (content.match(/<\/svg>/g) || []).length
|
|
||||||
|
|
||||||
if (openTags !== closeTags) {
|
|
||||||
throw new Error(`Malformed SVG file (mismatched svg tags): ${filename}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads custom SVG icons from the icons directory
|
|
||||||
*/
|
|
||||||
function loadCustomIcons(): void {
|
|
||||||
if (!existsSync(customIconsPath)) {
|
|
||||||
console.warn(`Custom icons directory not found: ${customIconsPath}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const files = readdirSync(customIconsPath)
|
|
||||||
const svgFiles = files.filter((file) => file.endsWith('.svg'))
|
|
||||||
|
|
||||||
if (svgFiles.length === 0) {
|
|
||||||
console.warn('No SVG files found in custom icons directory')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
svgFiles.forEach((file) => {
|
|
||||||
const name = file.replace('.svg', '')
|
|
||||||
const filePath = join(customIconsPath, file)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const content = readFileSync(filePath, 'utf-8')
|
|
||||||
validateSvgContent(content, file)
|
|
||||||
|
|
||||||
iconCollection.icons[name] = {
|
|
||||||
body: content
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
`Failed to load custom icon ${file}:`,
|
|
||||||
error instanceof Error ? error.message : error
|
|
||||||
)
|
|
||||||
// Continue loading other icons instead of failing the entire build
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
'Failed to read custom icons directory:',
|
|
||||||
error instanceof Error ? error.message : error
|
|
||||||
)
|
|
||||||
// Don't throw here - allow build to continue without custom icons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load icons when this module is imported
|
|
||||||
loadCustomIcons()
|
|
||||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -2344,6 +2344,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@iconify/tailwind/-/tailwind-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@iconify/tailwind/-/tailwind-1.2.0.tgz",
|
||||||
"integrity": "sha512-KgpIHWOTcRYw1XcoUqyNSrmYyfLLqZYu3AmP8zdfLk0F5TqRO8YerhlvlQmGfn7rJXgPeZN569xPAJnJ53zZxA==",
|
"integrity": "sha512-KgpIHWOTcRYw1XcoUqyNSrmYyfLLqZYu3AmP8zdfLk0F5TqRO8YerhlvlQmGfn7rJXgPeZN569xPAJnJ53zZxA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/types": "^2.0.0"
|
"@iconify/types": "^2.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -247,29 +247,9 @@ Icons are automatically imported using `unplugin-icons` - no manual imports need
|
|||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
The icon system has two layers:
|
The icon system is configured in `vite.config.mts`:
|
||||||
|
|
||||||
1. **Build-time Processing** (`build/customIconCollection.ts`):
|
|
||||||
- Scans `src/assets/icons/custom/` for SVG files
|
|
||||||
- Validates SVG content and structure
|
|
||||||
- Creates Iconify collection for Tailwind CSS
|
|
||||||
- Provides error handling for malformed files
|
|
||||||
|
|
||||||
2. **Vite Runtime** (`vite.config.mts`):
|
|
||||||
- Enables direct SVG import as Vue components
|
|
||||||
- Supports dynamic icon loading
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Build script creates Iconify collection
|
|
||||||
export const iconCollection: IconifyCollection = {
|
|
||||||
prefix: 'comfy',
|
|
||||||
icons: {
|
|
||||||
'workflow': { body: '<svg>...</svg>' },
|
|
||||||
'node': { body: '<svg>...</svg>' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vite configuration for component-based usage
|
|
||||||
Icons({
|
Icons({
|
||||||
compiler: 'vue3',
|
compiler: 'vue3',
|
||||||
customCollections: {
|
customCollections: {
|
||||||
@@ -291,9 +271,8 @@ Icons are fully typed. If TypeScript doesn't recognize a new custom icon:
|
|||||||
### Icon Not Showing
|
### Icon Not Showing
|
||||||
1. **Check filename**: Must be kebab-case without special characters
|
1. **Check filename**: Must be kebab-case without special characters
|
||||||
2. **Restart dev server**: Required after adding new icons
|
2. **Restart dev server**: Required after adding new icons
|
||||||
3. **Verify SVG**: Ensure it's valid SVG syntax (build script validates automatically)
|
3. **Verify SVG**: Ensure it's valid SVG syntax
|
||||||
4. **Check console**: Look for Vue component resolution errors
|
4. **Check console**: Look for Vue component resolution errors
|
||||||
5. **Build script errors**: Check console during build - malformed SVGs are logged but don't break builds
|
|
||||||
|
|
||||||
### Icon Wrong Color
|
### Icon Wrong Color
|
||||||
- Replace hardcoded colors with `currentColor`
|
- Replace hardcoded colors with `currentColor`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
import { addDynamicIconSelectors } from '@iconify/tailwind'
|
import { addDynamicIconSelectors } from '@iconify/tailwind'
|
||||||
|
|
||||||
import { iconCollection } from './build/customIconCollection.ts'
|
import { iconCollection } from './build/customIconCollection.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||||
|
|||||||
Reference in New Issue
Block a user