diff --git a/REFACTORING_SUMMARY.md b/REFACTORING_SUMMARY.md new file mode 100644 index 00000000..5e34d650 --- /dev/null +++ b/REFACTORING_SUMMARY.md @@ -0,0 +1,181 @@ +# WebContainer Refactoring Summary + +## Overview + +The WebContainer component has been successfully refactored from a monolithic 1094-line file into a modular, service-based architecture with proper dependency injection. + +## Refactoring Completed + +### 1. WebContainer Setup Logic Extracted ✅ + +**Before**: All logic in `components/web-container.tsx` (1094 lines) + +**After**: Separated into focused services: +- `lib/services/webcontainer/webcontainer-manager.ts` - Core WebContainer lifecycle +- `lib/services/webcontainer/server-manager.ts` - Server operations +- `lib/services/webcontainer/file-manager.ts` - File system operations +- `lib/services/webcontainer/project-setup-service.ts` - Project orchestration + +### 2. Project Templates System ✅ + +**Created reusable project templates**: +- `lib/services/project-templates/base-template.ts` - Abstract base class +- `lib/services/project-templates/html-template.ts` - HTML/CSS/JS projects +- `lib/services/project-templates/react-template.ts` - React with Vite & TypeScript +- `lib/services/project-templates/generic-template.ts` - Node.js/JavaScript projects +- `lib/services/project-templates/template-registry.ts` - Template management + +### 3. Dependency Injection Pattern ✅ + +**Implemented proper DI container**: +- `lib/services/container.ts` - Service container with dependency management +- Singleton pattern for global service access +- Automatic dependency resolution +- Lifecycle management and cleanup + +### 4. AI Team Coordination ✅ + +**Extracted AI team logic**: +- `lib/services/ai-team/ai-team-coordinator.ts` - AI team workflow management +- Agent status tracking and updates +- Integration with project setup services + +### 5. Refactored Component ✅ + +**Created new component**: +- `components/web-container-refactored.tsx` - Clean component using services +- 70% reduction in component code +- Clear separation of concerns +- Improved maintainability + +## Architecture Benefits + +### Before Refactoring +- Single 1094-line file +- Mixed responsibilities +- Hardcoded project setups +- Difficult to test +- No reusability + +### After Refactoring +- Modular service architecture +- Clear separation of concerns +- Reusable project templates +- Dependency injection for testability +- Easy to extend with new project types + +## Services Overview + +### WebContainerManager +```typescript +- initialize(): Promise +- getInstance(): any | null +- addCleanupFunction(cleanup: () => void): void +- teardown(): Promise +``` + +### ServerManager +```typescript +- startDevelopmentServer(container, command): Promise +- startHTMLServer(container): Promise +- stopServer(): void +- getStatus(): ServerStatus +``` + +### FileManager +```typescript +- mountFiles(files): Promise +- writeFile(path, contents): Promise +- readFile(path): Promise +- createDirectory(path): Promise +``` + +### ProjectSetupService +```typescript +- setupProject(type, options): Promise +- getServerStatus(): ServerStatus +- stopServer(): void +- teardown(): Promise +``` + +### TemplateRegistry +```typescript +- detectProjectType(code): BaseProjectTemplate +- setupProject(type, options): Promise +- getAvailableTemplates(): TemplateInfo[] +- registerTemplate(template): void +``` + +### AITeamCoordinator +```typescript +- startDevelopment(instructions): Promise +- getAgents(): AIAgent[] +- getServerStatus(): ServerStatus +- teardown(): Promise +``` + +## Usage Example + +```typescript +import { getContainer } from '@/lib/services/container'; + +// Get the DI container +const container = getContainer(); + +// Create project setup service with callbacks +const projectSetupService = container.createProjectSetupService({ + onOutput: (message) => console.log(message), + onProgress: (step, progress) => console.log(`${step}: ${progress}%`) +}); + +// Setup a React project +const result = await projectSetupService.setupProject('react', { + instructions: 'Create a dashboard with charts', + codeContent: '' +}); + +// Get server status +const status = projectSetupService.getServerStatus(); +``` + +## Testing Benefits + +The new architecture makes testing much easier: + +```typescript +// Mock individual services +const mockWebContainerManager = new MockWebContainerManager(); +const mockTemplateRegistry = new MockTemplateRegistry(); + +// Inject mocks into service +const projectSetupService = new ProjectSetupService({ + webContainerManager: mockWebContainerManager, + templateRegistry: mockTemplateRegistry +}); +``` + +## Future Extensions + +The modular architecture makes it easy to add: + +- New project templates (Vue, Angular, Svelte) +- Additional AI agents with specialized roles +- Custom deployment targets +- Enhanced file management features +- Project template marketplace + +## Migration Path + +The original `web-container.tsx` component remains functional. To migrate: + +1. Import the new component: `import WebContainerRefactored from './web-container-refactored'` +2. Replace usage gradually +3. Remove the old component when ready + +## Impact + +- **Maintainability**: 70% reduction in component complexity +- **Testability**: Services can be unit tested independently +- **Reusability**: Templates can be used across different components +- **Extensibility**: Easy to add new project types and features +- **Performance**: Better separation allows for optimization opportunities \ No newline at end of file diff --git a/components/web-container-refactored.tsx b/components/web-container-refactored.tsx new file mode 100644 index 00000000..285412cd --- /dev/null +++ b/components/web-container-refactored.tsx @@ -0,0 +1,323 @@ +'use client'; + +import React, { useEffect, useState, useRef, useCallback } from 'react'; +import { motion } from 'framer-motion'; +import { + Play, + Square, + RefreshCw, + AlertTriangle, + CheckCircle, + Loader, + Terminal, + FileText, + Code2, + Users, + Brain, +} from 'lucide-react'; +import { getContainer, DIContainer } from '@/lib/services/container'; +import { AIAgent } from '@/lib/services/ai-team/ai-team-coordinator'; +import { ServerStatus } from '@/lib/services/webcontainer/server-manager'; + +interface WebContainerProps { + code: string; + onCodeChange?: (code: string) => void; + className?: string; + aiTeamInstructions?: string; +} + +export default function WebContainerRefactored({ + code, + onCodeChange, + className, + aiTeamInstructions, +}: WebContainerProps) { + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const [terminalOutput, setTerminalOutput] = useState([]); + const [serverStatus, setServerStatus] = useState({ + isRunning: false, + url: null, + port: null, + }); + const [aiAgents, setAiAgents] = useState([ + { + id: 'architect', + name: 'System Architect', + role: 'Project structure & dependencies', + status: 'idle', + }, + { id: 'frontend', name: 'Frontend Developer', role: 'UI/UX components', status: 'idle' }, + { id: 'backend', name: 'Backend Developer', role: 'Server logic & APIs', status: 'idle' }, + { id: 'devops', name: 'DevOps Engineer', role: 'Build & deployment', status: 'idle' }, + ]); + + const iframeRef = useRef(null); + const containerRef = useRef(null); + + // Initialize container and services + useEffect(() => { + const initContainer = async () => { + setIsLoading(true); + setError(null); + + try { + addTerminalOutput('🔄 Initializing services...'); + + containerRef.current = getContainer(); + + // Setup AI team if instructions provided + if (aiTeamInstructions) { + await startAITeamDevelopment(aiTeamInstructions); + } else if (code && code.trim()) { + await setupCodeInContainer(code); + } + + setIsLoading(false); + addTerminalOutput('✅ Services initialized successfully'); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + setError(errorMessage); + addTerminalOutput(`❌ Error: ${errorMessage}`); + setIsLoading(false); + } + }; + + initContainer(); + + return () => { + // Cleanup on unmount + if (containerRef.current) { + containerRef.current.cleanup(); + } + }; + }, []); // Only run once on mount + + // Handle code changes + useEffect(() => { + const setupCode = async () => { + if (containerRef.current && code && code.trim()) { + await setupCodeInContainer(code); + } + }; + + setupCode(); + }, [code]); + + // Setup code in container using services + const setupCodeInContainer = async (codeContent: string) => { + if (!containerRef.current) return; + + try { + addTerminalOutput('📄 Setting up code in WebContainer...'); + + const projectSetupService = containerRef.current.createProjectSetupService({ + onOutput: addTerminalOutput, + onProgress: (step, progress) => { + addTerminalOutput(`📊 ${step}: ${progress}%`); + }, + }); + + const result = await projectSetupService.setupProject(undefined, { + codeContent, + instructions: '', + }); + + if (result.success) { + const status = projectSetupService.getServerStatus(); + setServerStatus(status); + addTerminalOutput('✅ Project setup completed successfully'); + } else { + throw new Error(result.message); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + addTerminalOutput(`❌ Setup error: ${errorMessage}`); + setError(errorMessage); + } + }; + + // AI Team Development Process + const startAITeamDevelopment = async (instructions: string) => { + if (!containerRef.current) return; + + try { + addTerminalOutput('🤖 Starting AI team development process...'); + + const aiTeamCoordinator = containerRef.current.createAITeamCoordinator({ + onAgentUpdate: setAiAgents, + onOutput: addTerminalOutput, + }); + + await aiTeamCoordinator.startDevelopment(instructions); + + const status = aiTeamCoordinator.getServerStatus(); + setServerStatus(status); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + addTerminalOutput(`❌ AI team error: ${errorMessage}`); + setError('AI team development failed'); + } + }; + + // Helper function to add terminal output + const addTerminalOutput = (output: string) => { + setTerminalOutput((prev) => [...prev, `${new Date().toLocaleTimeString()}: ${output}`]); + }; + + // Stop preview + const stopPreview = useCallback(() => { + if (containerRef.current) { + const projectSetupService = containerRef.current.createProjectSetupService(); + projectSetupService.stopServer(); + setServerStatus({ + isRunning: false, + url: null, + port: null, + }); + addTerminalOutput('🛑 Development server stopped'); + } + }, []); + + // Refresh preview + const refreshPreview = useCallback(() => { + if (iframeRef.current && serverStatus.url) { + iframeRef.current.src = iframeRef.current.src; + addTerminalOutput('🔄 Preview refreshed'); + } + }, [serverStatus.url]); + + if (isLoading) { + return ( +
+
+ +

Initializing WebContainer...

+
+ {terminalOutput.slice(-3).map((output, i) => ( +

+ {output} +

+ ))} +
+
+
+ ); + } + + return ( +
+ {/* AI Team Status */} + {aiTeamInstructions && ( +
+
+ +

AI Development Team

+
+
+ {aiAgents.map((agent) => ( +
+
+ + {agent.name} +
+

{agent.role}

+
+ {agent.status === 'idle' &&
} + {agent.status === 'working' && ( +
+ )} + {agent.status === 'complete' && ( + + )} + {agent.status === 'error' && } + {agent.status} +
+ {agent.currentTask && ( +

{agent.currentTask}

+ )} +
+ ))} +
+
+ )} + + {/* Controls */} +
+
+
+
+ {serverStatus.isRunning ? 'Running' : 'Stopped'} +
+ {serverStatus.url && {serverStatus.url}} +
+ +
+ + +
+
+ + {/* Content */} +
+ {/* Preview */} +
+ {serverStatus.url ? ( +