# LiveComponents Troubleshooting Guide **Common Issues and Solutions** This guide helps diagnose and resolve common LiveComponents problems. --- ## Table of Contents 1. [Component Not Responding](#component-not-responding) 2. [State Synchronization Issues](#state-synchronization-issues) 3. [CSRF Token Errors](#csrf-token-errors) 4. [Rate Limiting Issues](#rate-limiting-issues) 5. [SSE Connection Problems](#sse-connection-problems) 6. [Performance Issues](#performance-issues) 7. [File Upload Problems](#file-upload-problems) 8. [Fragment Rendering Issues](#fragment-rendering-issues) 9. [Browser Compatibility](#browser-compatibility) 10. [Debugging Tools](#debugging-tools) --- ## Component Not Responding ### Symptoms - Clicking buttons does nothing - Forms don't submit - No network requests in DevTools - Component appears static ### Diagnostic Steps **1. Check Component Initialization** ```javascript // Open browser console console.log(LiveComponent.components); // Should show active components // If empty, component not initialized ``` **2. Verify Component Markup** ```html
``` **3. Check JavaScript Loading** ```javascript // In browser console typeof LiveComponent !== 'undefined' // Should be true ``` **4. Inspect Browser Console** ``` F12 → Console Tab Look for JavaScript errors ``` ### Common Causes & Solutions #### Missing `data-component-id` ```html
``` #### JavaScript Not Loaded ```bash # Rebuild JavaScript assets npm run build # Check if file exists ls public/assets/js/livecomponent.js # Development mode npm run dev ``` #### HTTPS Not Enabled ```bash # LiveComponents requires HTTPS # Start with HTTPS make up # Access via https://localhost # ✅ Correct http://localhost # ❌ Wrong - will fail ``` #### Component Class Not Found ```php // Verify class exists and namespace is correct namespace App\Application\LiveComponents; final class MyComponent extends LiveComponent { // Implementation } // In controller LiveComponent::mount(MyComponent::class) // ✅ LiveComponent::mount('MyComponent') // ❌ Wrong ``` --- ## State Synchronization Issues ### Symptoms - Property changes don't reflect in UI - UI updates but server state wrong - State resets unexpectedly ### Diagnostic Steps **1. Check LiveProp Attribute** ```php // ❌ Wrong - missing attribute public string $name = ''; // ✅ Correct #[LiveProp] public string $name = ''; ``` **2. Verify Property Type Compatibility** ```php // ✅ Supported types #[LiveProp] public string $text; #[LiveProp] public int $count; #[LiveProp] public float $price; #[LiveProp] public bool $active; #[LiveProp] public array $items; // ❌ Not supported - can't serialize #[LiveProp] public \Closure $callback; #[LiveProp] public Resource $handle; #[LiveProp] public PDO $connection; ``` **3. Inspect Current State** ```javascript // Get component state const component = LiveComponent.getComponent('component-id'); console.log('Current state:', component.state); ``` ### Common Causes & Solutions #### Property Not Marked as LiveProp ```php // Problem: Property changes not synced public string $searchTerm = ''; // ❌ Missing #[LiveProp] #[LiveAction] public function search(): void { // $this->searchTerm not synced with client $this->results = $this->searchService->search($this->searchTerm); } // Solution: Add attribute #[LiveProp] public string $searchTerm = ''; // ✅ Now syncs ``` #### Complex Object Serialization ```php // Problem: Object can't be serialized #[LiveProp] public User $user; // ❌ Complex object // Solution: Use Value Object or primitives #[LiveProp] public string $userId; private User $user; // Not serialized public function hydrate(array $state): void { parent::hydrate($state); // Reload user from ID $this->user = $this->userRepository->find($this->userId); } ``` #### State Checksum Mismatch ```javascript // Monitor checksum errors window.addEventListener('livecomponent:error', (e) => { if (e.detail.code === 'CHECKSUM_MISMATCH') { console.error('State corrupted - refreshing component'); LiveComponent.refresh(e.detail.componentId); } }); ``` --- ## CSRF Token Errors ### Symptoms - "CSRF token mismatch" error - 403 Forbidden responses - Actions fail silently ### Diagnostic Steps **1. Check CSRF Meta Tag** ```html ``` **2. Verify Token in Requests** ``` F12 → Network Tab → Select request → Headers Should have: X-CSRF-Token: {token} ``` **3. Check Token Expiry** ```php // .env configuration CSRF_TOKEN_LIFETIME=7200 // 2 hours (default) ``` ### Common Causes & Solutions #### Missing CSRF Meta Tag ```html My App My App ``` #### Token Expired ```javascript // Automatic token refresh window.addEventListener('livecomponent:error', (e) => { if (e.detail.code === 'CSRF_TOKEN_EXPIRED') { // Refresh token LiveComponent.refreshCsrfToken().then(() => { // Retry failed action LiveComponent.retryLastAction(); }); } }); ``` #### Session Cleared ```php // Problem: Session expired/cleared // Solution: Redirect to login window.addEventListener('livecomponent:error', (e) => { if (e.detail.code === 'SESSION_EXPIRED') { window.location.href = '/login?redirect=' + window.location.pathname; } }); ``` #### Development vs Production ```env # Development - lenient CSRF_TOKEN_LIFETIME=86400 # 24 hours # Production - strict CSRF_TOKEN_LIFETIME=3600 # 1 hour CSRF_REGENERATE_ON_ACTION=true ``` --- ## Rate Limiting Issues ### Symptoms - "Too many requests" error (429) - Actions blocked after rapid clicks - "Retry-After" headers in response ### Diagnostic Steps **1. Check Rate Limit Configuration** ```env LIVECOMPONENT_RATE_LIMIT=60 # Default: 60/minute LIVECOMPONENT_RATE_LIMIT_WINDOW=60 # Window in seconds ``` **2. Monitor Rate Limit Events** ```javascript window.addEventListener('livecomponent:rate-limited', (e) => { console.warn('Rate limited:', { action: e.detail.action, retryAfter: e.detail.retryAfter }); }); ``` **3. Check Component-Specific Limits** ```php #[RateLimit(requests: 10, window: 60)] final class SearchComponent extends LiveComponent { // More restrictive than global limit } ``` ### Common Causes & Solutions #### Too Aggressive Rate Limit ```env # Problem: Rate limit too low LIVECOMPONENT_RATE_LIMIT=10 # Too restrictive # Solution: Increase for normal usage LIVECOMPONENT_RATE_LIMIT=60 # More reasonable ``` #### Rapid User Actions ```php // Problem: User clicking too fast #[LiveAction] public function search(): void { // Triggered on every keystroke } // Solution: Use debouncing ``` ```html ``` #### Bot/Scraper Activity ```php use App\Framework\Http\Middlewares\RateLimitMiddleware; // Implement stricter limits for suspicious patterns #[RateLimit(requests: 5, window: 300)] // 5 per 5 minutes final class PublicApiComponent extends LiveComponent { // Public-facing, needs protection } ``` --- ## SSE Connection Problems ### Symptoms - Real-time updates not working - Connection drops frequently - "SSE disconnected" in console ### Diagnostic Steps **1. Verify HTTPS** ``` SSE requires HTTPS in production https://localhost ✅ http://localhost ❌ ``` **2. Check SSE Configuration** ```env LIVECOMPONENT_SSE_ENABLED=true LIVECOMPONENT_SSE_HEARTBEAT=15 # Heartbeat interval ``` **3. Monitor SSE Connection** ```javascript window.addEventListener('livecomponent:sse-connected', () => { console.log('SSE connected'); }); window.addEventListener('livecomponent:sse-disconnected', (e) => { console.error('SSE disconnected:', e.detail.reason); }); ``` **4. Check Server Logs** ```bash docker logs php | grep SSE ``` ### Common Causes & Solutions #### HTTPS Not Enabled ```bash # Problem: HTTP used in production # Solution: Enable HTTPS # Development make up # Automatically uses HTTPS # Production # Configure SSL certificates in nginx/apache ``` #### Firewall Blocking SSE ```nginx # nginx configuration location /livecomponent/sse { proxy_pass http://php-fpm; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; proxy_cache off; proxy_read_timeout 86400s; # 24 hours } ``` #### Connection Timeout ```php // Increase SSE timeout set_time_limit(0); // No timeout ignore_user_abort(true); ``` #### Auto-Reconnection Not Working ```javascript // Manual reconnection logic let reconnectAttempts = 0; const maxReconnectAttempts = 5; window.addEventListener('livecomponent:sse-disconnected', (e) => { if (reconnectAttempts < maxReconnectAttempts) { const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000); setTimeout(() => { console.log(`Reconnecting SSE (attempt ${reconnectAttempts + 1})`); LiveComponent.reconnectSse(e.detail.componentId); reconnectAttempts++; }, delay); } }); window.addEventListener('livecomponent:sse-connected', () => { reconnectAttempts = 0; // Reset on successful connection }); ``` --- ## Performance Issues ### Symptoms - Slow action responses (>500ms) - UI freezes during updates - High memory usage - Browser lag ### Diagnostic Steps **1. Enable Performance Profiling** ```javascript localStorage.setItem('livecomponent_devtools', 'true'); localStorage.setItem('livecomponent_profiling', 'true'); location.reload(); ``` **2. Check Action Latency** ```javascript window.addEventListener('livecomponent:action-executed', (e) => { if (e.detail.duration > 200) { console.warn('Slow action:', { action: e.detail.action, duration: e.detail.duration }); } }); ``` **3. Monitor Memory Usage** ``` F12 → Performance Tab → Memory Record session and analyze heap snapshots ``` **4. Analyze Network Requests** ``` F12 → Network Tab Check: - Request count (should be low with batching) - Payload sizes - Response times ``` ### Common Causes & Solutions #### Large Component State ```php // Problem: Serializing too much data #[LiveProp] public array $allProducts = []; // ❌ 10,000 products // Solution: Pagination #[LiveProp] public int $page = 1; #[LiveProp] public int $perPage = 50; private array $products = []; // ✅ Not serialized public function mount(): void { $this->loadPage(); } private function loadPage(): void { $this->products = $this->productRepository->paginate( page: $this->page, perPage: $this->perPage ); } ``` #### No Fragment Rendering ```php // Problem: Re-rendering entire component #[LiveAction] public function updateStats(): void { $this->stats = $this->calculateStats(); // Full component re-render ❌ } // Solution: Use fragments #[LiveAction] #[Fragment('stats-section')] public function updateStats(): void { $this->stats = $this->calculateStats(); // Only stats fragment re-renders ✅ } ``` #### N+1 Query Problem ```php // Problem: N+1 queries public function render(): string { foreach ($this->orders as $order) { $customer = $this->customerRepository->find($order->customerId); // ❌ Query per order } } // Solution: Eager loading public function mount(): void { $this->orders = $this->orderRepository->findWithCustomers(); // ✅ Single query with JOIN } ``` #### Too Many Components ``` Problem: >100 components on page Solution: 1. Lazy load components 2. Use virtual scrolling 3. Implement pagination ``` See [Performance Guide](performance-guide.md) for comprehensive optimization strategies. --- ## File Upload Problems ### Symptoms - Upload fails silently - Progress stuck at 0% - Chunk upload errors - File size exceeded errors ### Diagnostic Steps **1. Check Upload Configuration** ```html ``` **2. Monitor Upload Events** ```javascript window.addEventListener('livecomponent:upload-progress', (e) => { console.log(`Upload: ${e.detail.progress}%`); }); window.addEventListener('livecomponent:upload-error', (e) => { console.error('Upload failed:', e.detail.error); }); ``` **3. Check Server Limits** ```php // php.ini upload_max_filesize = 100M post_max_size = 100M max_execution_time = 300 ``` ### Common Causes & Solutions #### File Size Exceeds Limit ```html ``` ```javascript // Client-side validation window.addEventListener('livecomponent:upload-error', (e) => { if (e.detail.code === 'FILE_TOO_LARGE') { alert(`File too large. Max size: ${e.detail.maxSize / 1024 / 1024}MB`); } }); ``` #### Chunk Upload Failure ```php // Server-side: Implement retry logic final class ChunkUploadHandler { public function storeChunk( string $uploadId, int $chunkIndex, string $data ): void { $attempts = 0; $maxAttempts = 3; while ($attempts < $maxAttempts) { try { $this->storage->put( "uploads/{$uploadId}/chunk_{$chunkIndex}", $data ); return; } catch (\Exception $e) { $attempts++; if ($attempts >= $maxAttempts) { throw $e; } usleep(100000 * $attempts); // Exponential backoff } } } } ``` #### Upload State Lost ```php // Problem: Upload state not persisted // Solution: Store upload state final class UploadStateRepository { public function saveState(UploadState $state): void { $this->cache->set( "upload_state:{$state->uploadId}", serialize($state), Duration::fromHours(24) ); } public function restoreState(string $uploadId): ?UploadState { $data = $this->cache->get("upload_state:{$uploadId}"); return $data ? unserialize($data) : null; } } ``` --- ## Fragment Rendering Issues ### Symptoms - Fragment not updating - Entire component re-renders - Focus lost after update - Nested fragments broken ### Diagnostic Steps **1. Verify Fragment Markup** ```html
``` **2. Check Action Attribute** ```php #[LiveAction] #[Fragment('section-name')] // Must match HTML public function updateSection(): void { // Update logic } ``` **3. Monitor Fragment Updates** ```javascript window.addEventListener('livecomponent:fragment-updated', (e) => { console.log('Fragment updated:', { name: e.detail.fragmentName, duration: e.detail.duration }); }); ``` ### Common Causes & Solutions #### Fragment Name Mismatch ```php // Problem: Names don't match #[Fragment('user-stats')] // ❌ kebab-case in PHP public function updateStats(): void { } ``` ```html
``` ```php // Solution: Use consistent naming #[Fragment('user-stats')] // ✅ kebab-case ``` ```html
``` #### Missing Fragment Attribute ```php // Problem: Fragment specified but no HTML marker #[LiveAction] #[Fragment('results')] public function search(): void { } // Template missing fragment marker
{result.title}
// Solution: Add fragment marker
{result.title}
``` #### Focus Lost After Update ```javascript // Problem: Input focus lost during fragment update // Solution: Framework preserves focus automatically // If not working, check: // 1. Is input inside fragment?
// 2. Does input have stable ID? ✅ Has ID ❌ No ID ``` --- ## Browser Compatibility ### Symptoms - Works in Chrome but not Safari - Mobile browser issues - Older browser errors ### Supported Browsers - Chrome/Edge: 90+ - Firefox: 88+ - Safari: 14+ - Mobile Safari: 14+ - Mobile Chrome: 90+ ### Common Issues #### ES2020 Features Not Supported ```javascript // Problem: Older browser lacks ES2020 // Solution: Build with polyfills // vite.config.js export default defineConfig({ build: { target: 'es2015', // Broader compatibility polyfillModulePreload: true } }); ``` #### EventSource Not Supported ```javascript // Check SSE support if (typeof EventSource === 'undefined') { console.warn('SSE not supported - real-time updates disabled'); // Fallback to polling } ``` #### iOS Safari Issues ```javascript // iOS Safari has stricter CORS requirements // Ensure proper CORS headers // PHP header('Access-Control-Allow-Origin: https://yourdomain.com'); header('Access-Control-Allow-Credentials: true'); ``` --- ## Debugging Tools ### DevTools Panel **Enable DevTools**: ```env LIVECOMPONENT_DEVTOOLS_ENABLED=true ``` Or via localStorage: ```javascript localStorage.setItem('livecomponent_devtools', 'true'); location.reload(); ``` **Features**: - Component tree inspection - Action log with timing - Event log - Performance profiling - Network monitoring - DOM badges ### Console Commands ```javascript // Get all components LiveComponent.components // Get specific component const component = LiveComponent.getComponent('component-id'); // Inspect state console.log(component.state); // Execute action manually LiveComponent.executeAction('component-id', 'actionName', { param: 'value' }); // Refresh component LiveComponent.refresh('component-id'); // Get performance metrics LiveComponent.getMetrics('component-id'); ``` ### Server-Side Debugging ```php // Log component state $this->logger->debug('Component state', [ 'component' => static::class, 'state' => $this->getState() ]); // Performance tracking $start = hrtime(true); $result = $this->expensiveOperation(); $duration = (hrtime(true) - $start) / 1e6; $this->logger->info('Operation completed', [ 'duration_ms' => $duration ]); ``` ### Network Debugging ``` F12 → Network Tab → Filter: livecomponent Check: - Request payloads - Response times - Error responses - Batching efficiency ``` --- ## Getting Help ### Before Asking for Help 1. **Check this guide** for common solutions 2. **Enable DevTools** and check console 3. **Reproduce in isolation** (minimal example) 4. **Gather error messages** (browser console + server logs) ### Reporting Issues Include: - Browser + version - PHP version - Framework version - Component code (minimal reproduction) - Error messages - Steps to reproduce ### Resources - **Documentation**: [Getting Started](01-getting-started.md), [API Reference](api-reference.md) - **Examples**: `src/Application/LiveComponents/` - **Tests**: `tests/e2e/livecomponents-*.spec.js` - **Security**: security@example.com - **Bugs**: GitHub Issues --- **Next**: [FAQ](faq.md) →