'connected', 'timestamp' => date('c'), 'message' => 'Hot Reload server started' ]) . "\n\n"; flush(); // Keep connection alive and watch for changes $lastCheck = time(); while (connection_aborted() === 0) { // Check for file changes every 500ms $changes = $fileWatcher->watchOnce($watchPatterns, $ignorePatterns); foreach ($changes as $change) { $reloadType = determineReloadType($change); echo "event: reload\n"; echo "data: " . json_encode([ 'type' => $reloadType->value, 'file' => $change->getPath(), 'timestamp' => $change->getTimestamp()->format('c'), 'message' => 'File changed: ' . basename($change->getPath()) ]) . "\n\n"; flush(); } // Send heartbeat every 30 seconds if (time() - $lastCheck >= 30) { echo "event: heartbeat\n"; echo "data: " . json_encode([ 'timestamp' => date('c'), 'message' => 'Connection alive' ]) . "\n\n"; flush(); $lastCheck = time(); } // Small delay to prevent high CPU usage usleep(500000); // 500ms } function determineReloadType(FileChangeEvent $event): ReloadType { $path = $event->getPath(); // PHP files need full page reload if (str_ends_with($path, '.php')) { return ReloadType::FULL; } // CSS files can use hot replacement if (str_ends_with($path, '.css')) { return ReloadType::CSS; } // JS modules can use HMR if supported if (str_ends_with($path, '.js') || str_ends_with($path, '.ts')) { return ReloadType::HMR; } // Templates need full reload if (str_ends_with($path, '.view.php')) { return ReloadType::FULL; } return ReloadType::FULL; }