isFile()) { continue; } $path = $file->getPathname(); // Only watch specific file types if (!preg_match('/\.(php|view\.php|css|js|ts)$/', $path)) { continue; } $mtime = $file->getMTime(); if (!isset($fileCache[$path])) { $fileCache[$path] = $mtime; } elseif ($fileCache[$path] < $mtime) { $changes[] = [ 'path' => $path, 'type' => 'modified', 'time' => $mtime ]; $fileCache[$path] = $mtime; } } return $changes; } // Send initial connection event echo "event: connected\n"; echo "data: " . json_encode([ 'status' => 'connected', 'timestamp' => date('c'), 'message' => 'Hot Reload server started' ]) . "\n\n"; flush(); // Initialize file cache foreach ($watchedDirs as $dir) { scanDirectory($dir, $fileCache); } $lastHeartbeat = time(); // Keep connection alive and watch for changes while (connection_aborted() === 0) { $hasChanges = false; // Check each watched directory foreach ($watchedDirs as $dir) { $changes = scanDirectory($dir, $fileCache); foreach ($changes as $change) { $reloadType = 'full'; if (str_ends_with($change['path'], '.css')) { $reloadType = 'css'; } elseif (str_ends_with($change['path'], '.js') || str_ends_with($change['path'], '.ts')) { $reloadType = 'hmr'; } echo "event: reload\n"; echo "data: " . json_encode([ 'type' => $reloadType, 'file' => basename($change['path']), 'path' => $change['path'], 'timestamp' => date('c'), 'message' => 'File changed: ' . basename($change['path']) ]) . "\n\n"; flush(); $hasChanges = true; } } // Send heartbeat every 30 seconds if (time() - $lastHeartbeat >= 30) { echo "event: heartbeat\n"; echo "data: " . json_encode([ 'timestamp' => date('c'), 'message' => 'Connection alive' ]) . "\n\n"; flush(); $lastHeartbeat = time(); } // Small delay to prevent high CPU usage usleep(500000); // 500ms }