Icons - v2.1.1
Architecture Overview
This document explains the architectural design of ArtisanPack UI Icons v2.0, including the adapter pattern implementation, integration with blade-ui-kit/blade-icons, and the hybrid registration system.
System Architecture
ArtisanPack UI Icons v2.0 is built on the adapter pattern, transforming from a hardcoded icon provider into an extensibility layer that integrates custom icon sets with Laravel's Blade component system.
High-Level Architecture
┌─────────────────────────────────────────────────────────────┐
│ ArtisanPack UI Icons v2.0 │
│ (Extensibility Layer) │
├─────────────────────────────────────────────────────────────┤
│ Config-Based Registration │ Event-Driven Registration │
│ ┌─────────────────────────┐ │ ┌─────────────────────────┐ │
│ │ config/artisanpack/icons.php │ │ │ Third-Party Packages │ │
│ │ │ │ │ via Filter Hooks │ │
│ └─────────────────────────┘ │ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ IconsServiceProvider │
│ (Hybrid Registration) │
├─────────────────────────────────────────────────────────────┤
│ blade-ui-kit/blade-icons │
│ (SVG Component Rendering) │
├─────────────────────────────────────────────────────────────┤
│ Laravel Blade Engine │
│ (Component Resolution) │
└─────────────────────────────────────────────────────────────┘
Core Components
- Configuration System - Manages user-defined icon sets
- Event System - Enables third-party package integration
- Service Provider - Orchestrates registration and integration
- Adapter Layer - Bridges custom icon sets with blade-ui-kit
- Component System - Renders icons as Blade components
Adapter Pattern Implementation
The v2.0 architecture implements the adapter pattern to bridge the gap between custom icon sets and the standardized blade-ui-kit/blade-icons system.
Traditional Approach (v1.x)
// v1.x - Hardcoded approach
class Icons {
protected $icons = [
'home' => '<svg>...</svg>',
'user' => '<svg>...</svg>',
// 17,000+ hardcoded icons
];
}
Adapter Approach (v2.0)
// v2.0 - Adapter approach
class IconsServiceProvider {
public function boot() {
// Adapt custom icon sets to BladeIcons format
$this->registerIcons();
}
protected function registerIcons() {
$iconSets = $this->collectIconSets();
foreach ($iconSets as $set) {
BladeIcons::add($set['prefix'], [
'path' => $set['path'],
'prefix' => $set['prefix'],
]);
}
}
}
Benefits of Adapter Pattern
- Flexibility - Use any SVG icon collection
- Performance - No hardcoded arrays, minimal memory usage
- Extensibility - Third-party packages can register icon sets
- Maintainability - Clear separation of concerns
- Standards Compliance - Leverages established blade-ui-kit patterns
Integration with blade-ui-kit/blade-icons
The package integrates deeply with blade-ui-kit/blade-icons to provide seamless SVG component rendering.
BladeIcons Factory Integration
use BladeUI\Icons\Factory as BladeIcons;
// Register icon set with BladeIcons factory
BladeIcons::add('prefix', [
'path' => '/path/to/svg/files',
'prefix' => 'prefix',
]);
// This enables components like:
// <x-icon-prefix-home />
// <x-icon-prefix-user />
Component Resolution Flow
1. Blade Template: <x-icon-fa-home class="w-6 h-6" />
↓
2. Laravel Component Resolution
↓
3. BladeIcons Factory Lookup (prefix: 'fa', name: 'home')
↓
4. SVG File Loading (/path/to/fa/home.svg)
↓
5. SVG Content Rendering with Attributes
↓
6. Final HTML: <svg class="w-6 h-6">...</svg>
Deferred Registration
Icon registration is deferred until the BladeCompiler is resolved to ensure proper initialization order:
$this->app->callAfterResolving(BladeCompiler::class, function () {
$this->registerIcons();
});
Hybrid Registration System
The v2.0 architecture implements a hybrid registration system that combines two registration methods.
Registration Sources
1. Config-Based Registration
- Source:
config/artisanpack/icons.php - Priority: High (overrides event-driven)
- Use Case: User-configured icon sets
- Control: Direct user control
// config/artisanpack/icons.php
return [
'sets' => [
['path' => resource_path('icons/fa'), 'prefix' => 'fa'],
['path' => resource_path('icons/custom'), 'prefix' => 'custom'],
],
];
2. Event-Driven Registration
- Source: Third-party packages via filter hooks
- Priority: Low (config overrides)
- Use Case: Package-provided icon sets
- Control: Programmatic registration
// In a package service provider
addFilter('ap.icons.register-icon-sets', function ($sets) {
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'mypackage'
);
return $sets;
});
Registration Process
protected function collectIconSets(): array
{
// 1. Collect event-driven registrations
$eventSets = apply_filters('ap.icons.register-icon-sets', []);
// 2. Get config-based registrations
$configSets = config('artisanpack.icons.sets', []);
// 3. Merge with config precedence
$allSets = array_merge($eventSets, $configSets);
// 4. Validate and filter
return array_filter($allSets, [$this, 'validateIconSet']);
}
protected function validateIconSet(array $set): bool
{
return isset($set['path']) &&
isset($set['prefix']) &&
is_dir($set['path']);
}
Configuration Reference
Configuration Structure
<?php
// config/artisanpack/icons.php
return [
/*
|--------------------------------------------------------------------------
| Custom Icon Sets
|--------------------------------------------------------------------------
|
| Register your custom SVG icon sets here. Each set requires:
| - path: Absolute path to directory containing SVG files
| - prefix: Unique prefix for Blade components (e.g., 'fa', 'hero')
|
*/
'sets' => [
// Font Awesome Pro icons
[
'path' => resource_path('icons/fontawesome/solid'),
'prefix' => 'fas',
],
[
'path' => resource_path('icons/fontawesome/regular'),
'prefix' => 'far',
],
[
'path' => resource_path('icons/fontawesome/brands'),
'prefix' => 'fab',
],
// Heroicons
[
'path' => resource_path('icons/heroicons/outline'),
'prefix' => 'hero-outline',
],
[
'path' => resource_path('icons/heroicons/solid'),
'prefix' => 'hero-solid',
],
// Custom application icons
[
'path' => resource_path('icons/custom'),
'prefix' => 'custom',
],
],
];
Configuration Validation Rules
Each icon set must follow these rules:
- path (string, required): Absolute path to directory containing SVG files
- prefix (string, required): Unique prefix for Blade components (alphanumeric + hyphens)
- Directory must exist: The path must point to an existing, readable directory
- Contains SVG files: Directory should contain at least one
.svgfile
Invalid Configuration Examples
// ❌ Missing required keys
['path' => '/path/to/icons'], // Missing prefix
// ❌ Non-existent directory
['path' => '/non/existent/path', 'prefix' => 'test'],
// ❌ Invalid prefix characters
['path' => resource_path('icons'), 'prefix' => 'my_icons!'],
// ❌ Conflicting prefixes (will cause overwrites)
['path' => resource_path('icons/set1'), 'prefix' => 'fa'],
['path' => resource_path('icons/set2'), 'prefix' => 'fa'], // Conflict!
Performance Characteristics
Memory Usage
| Aspect | v1.x | v2.0 |
|---|---|---|
| Startup Memory | ~50MB (17K+ icons) | ~1KB (metadata only) |
| Per Icon | Preloaded in memory | Loaded on-demand |
| Total Reduction | - | 95%+ improvement |
Loading Performance
v1.x Loading Process:
Application Start → Load 17K+ Icons → Memory Allocation → Ready
~500ms ~2GB RAM
v2.0 Loading Process:
Application Start → Register Metadata → Ready → Load Icon on Use
~10ms ~1KB RAM ~5ms per icon
Caching Strategy
The v2.0 architecture leverages multiple caching layers:
- Configuration Caching - Laravel's
config:cachecaches merged configuration - BladeIcons Caching - blade-ui-kit handles SVG content caching
- Blade Component Caching - Laravel caches compiled components
- Browser Caching - SVG content benefits from HTTP caching
Error Handling and Validation
Configuration Validation
protected function validateIconSet(array $set): bool
{
// Required keys validation
if (!isset($set['path']) || !isset($set['prefix'])) {
$this->logWarning('Icon set missing required keys', $set);
return false;
}
// Path existence validation
if (!is_dir($set['path'])) {
$this->logWarning("Icon directory not found: {$set['path']}", $set);
return false;
}
// Path readability validation
if (!is_readable($set['path'])) {
$this->logWarning("Icon directory not readable: {$set['path']}", $set);
return false;
}
// Prefix format validation
if (!preg_match('/^[a-zA-Z0-9-]+$/', $set['prefix'])) {
$this->logWarning("Invalid prefix format: {$set['prefix']}", $set);
return false;
}
return true;
}
Runtime Error Handling
protected function registerIconSet(array $set): void
{
try {
BladeIcons::add($set['prefix'], $set);
} catch (\Exception $e) {
$this->logError("Failed to register icon set '{$set['prefix']}'", [
'error' => $e->getMessage(),
'set' => $set,
]);
}
}
Troubleshooting Guide
Common Issues and Solutions
1. Icons Not Displaying
Symptoms:
- Blank space where icon should be
- Component not found errors
- Invalid component name errors
Solutions:
// Check configuration
php artisan tinker
> config('artisanpack.icons.sets')
// Verify directory exists
> is_dir(resource_path('icons/fontawesome'))
// Check for SVG files
> glob(resource_path('icons/fontawesome') . '/*.svg')
// Clear caches
php artisan config:clear
php artisan view:clear
2. Prefix Conflicts
Symptoms:
- Icons from one set override another
- Unexpected icon rendering
Solutions:
// Check for duplicate prefixes in config
$sets = config('artisanpack.icons.sets');
$prefixes = array_column($sets, 'prefix');
$duplicates = array_diff_assoc($prefixes, array_unique($prefixes));
// Use unique prefixes
'prefix' => 'mypackage-admin' // Instead of generic 'admin'
3. Performance Issues
Symptoms:
- Slow page loading
- High memory usage
- Long application startup time
Solutions:
// Check icon set sizes
foreach (config('artisanpack.icons.sets') as $set) {
$count = count(glob($set['path'] . '/*.svg'));
echo "Set '{$set['prefix']}': {$count} icons\n";
}
// Consider splitting large sets
// Instead of one huge set:
['path' => resource_path('icons/all'), 'prefix' => 'all'],
// Use multiple smaller sets:
['path' => resource_path('icons/navigation'), 'prefix' => 'nav'],
['path' => resource_path('icons/actions'), 'prefix' => 'action'],
4. Third-Party Integration Issues
Symptoms:
- Package icons not appearing
- Filter hooks not firing
- Registration order conflicts
Solutions:
// Debug event-driven registration
addFilter('ap.icons.register-icon-sets', function (IconSetRegistration $registry) {
$beforeCount = count($registry->getSets());
\Log::debug('MyPackage registering icons', [
'path' => __DIR__ . '/../../resources/icons',
'prefix' => 'mypackage',
'existing_sets_count' => $beforeCount
]);
$registry->addSet(__DIR__ . '/../../resources/icons', 'mypackage');
\Log::debug('Icon sets after MyPackage', ['count' => count($registry->getSets())]);
return $registry;
});
FAQ
Q: Can I use multiple icon libraries together?
A: Yes, the hybrid system is designed for this. Each icon set uses a unique prefix, allowing you to mix Font Awesome, Heroicons, custom icons, etc.
Q: How do I handle icon naming conflicts?
A: Use descriptive prefixes. Instead of fa-home and hero-home, consider fa-solid-home and hero-outline-home.
Q: Can third-party packages override my config icons?
A: No, config-based registrations always take precedence over event-driven ones.
Q: What happens if an SVG file is malformed?
A: blade-ui-kit handles SVG parsing errors gracefully, typically rendering nothing or showing an error in development mode.
Q: How do I optimize for production?
A: Use php artisan config:cache, ensure SVG files are optimized, and consider using a CDN for icon assets.
Q: Can I register icons from cloud storage?
A: Currently, the system requires local file paths. Consider syncing cloud icons to local storage or extending the IconSetRegistration class to support remote paths.
Next Steps
- Review Installation Guide for setup instructions
- Explore Usage Examples for practical patterns
- Learn Extension API for package integration
- Check Migration Guide for v1.x upgrade path