diff --git a/FRONTEND_OPTIMIZATION_ARCHITECTURE.md b/FRONTEND_OPTIMIZATION_ARCHITECTURE.md new file mode 100644 index 000000000..137b8bf88 --- /dev/null +++ b/FRONTEND_OPTIMIZATION_ARCHITECTURE.md @@ -0,0 +1,168 @@ +# Frontend Optimization Architecture + +## Overview + +React frontend optimization extends Codeflash's existing JS/TS support with +framework-specific component discovery, React Profiler instrumentation, +memoization-focused optimization, and render-count-aware acceptance criteria. + +## Design Principle + +React optimization is a **framework plugin** under JS/TS, not a separate language. +It reuses the existing tree-sitter parser (JSX/TSX), Jest/Vitest runner, comparator, +and instrumentation infrastructure. Framework-specific logic is isolated in +`languages/javascript/frameworks/react/`. + +This pattern is designed to be reused for other frontend frameworks (Vue, Angular, Svelte) +by adding new directories under `languages/javascript/frameworks//`. + +## Architecture Diagram + + ┌──────────────────────────────────────────────────────────┐ + │ CLI Entry Point │ + │ codeflash optimize --file src/components/TaskList.tsx │ + └────────────────────────┬─────────────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ Framework Detection (detector.py) │ + │ package.json → FrameworkInfo(name="react", version=18) │ + └────────────────────────┬─────────────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ Component Discovery (discovery.py) │ + │ tree-sitter → ReactComponentInfo[] │ + │ PascalCase + JSX return + hooks → is_react_component │ + └────────────────────────┬─────────────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ Context Extraction (context.py + analyzer.py) │ + │ Component source + props interface + hooks + parents │ + │ + optimization opportunities (missing memo/useMemo) │ + └────────────────────────┬─────────────────────────────────┘ + │ + ┌──────────────┴──────────────┐ + ▼ ▼ + ┌───────────────────┐ ┌──────────────────────────────┐ + │ Test Generation │ │ Optimization Generation │ + │ (testgen.py) │ │ (aiservice + react prompts)│ + │ │ │ │ + │ React Testing │ │ React.memo wrapping │ + │ Library tests │ │ useMemo for computations │ + │ + re-render │ │ useCallback for handlers │ + │ counting tests │ │ Inline object elimination │ + └────────┬──────────┘ └──────────────┬───────────────┘ + │ │ + └──────────────┬─────────────────┘ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ Verification (existing Jest/Vitest runner) │ + │ Run existing + generated tests on original AND candidate │ + │ compare_test_results() → behavioral equivalence │ + └────────────────────────┬─────────────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ React Benchmarking (profiler.py + benchmarking.py)│ + │ React Profiler instrumentation → render count + duration │ + │ Parse !######REACT_RENDER:...######! markers │ + │ Compare original vs optimized render profiles │ + └────────────────────────┬─────────────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ Critic (render_efficiency_critic) │ + │ Accept if: render_count reduced >= 20% │ + │ OR: render_duration reduced >= threshold │ + │ AND: all tests pass (behavioral equivalence) │ + └────────────────────────┬─────────────────────────────────┘ + │ + ▼ + ┌──────────────────────────────────────────────────────────┐ + │ PR Creation │ + │ "Reduced re-renders from 47 → 3 (93.6% fewer)" │ + │ "Render time: 340ms → 12ms (28x faster)" │ + │ Includes generated tests + optimized component code │ + └──────────────────────────────────────────────────────────┘ + +## File Structure + + languages/javascript/ + ├── support.py # Delegates to react/ when framework detected + ├── treesitter.py # Reused — already handles JSX/TSX + ├── test_runner.py # Reused — runs Jest/Vitest + ├── comparator.py # Reused — compares test results + ├── instrument.py # Reused — capturePerf wrapping + ├── parse.py # Extended — parse REACT_RENDER markers + ├── frameworks/ + │ ├── __init__.py + │ ├── detector.py # Detect React from package.json + │ └── react/ + │ ├── __init__.py + │ ├── discovery.py # Find React components via tree-sitter + │ ├── analyzer.py # Detect optimization opportunities + │ ├── profiler.py # React Profiler instrumentation + │ ├── context.py # Component context extraction + │ ├── benchmarking.py # Render count/duration comparison + │ └── testgen.py # React Testing Library test helpers + +## Verification Model + +React optimization uses the SAME verification guarantees as code optimization: + + ┌─────────────────────────────────────────────────┐ + │ Behavioral Equivalence │ + │ │ + │ For each test invocation: │ + │ original.did_pass == candidate.did_pass │ + │ original.return_value ≡ candidate.return_value │ + │ original.stdout ≡ candidate.stdout │ + │ │ + │ PLUS for React: │ + │ candidate.render_count <= original.render_count │ + │ candidate.render_duration < original.render_duration │ + └─────────────────────────────────────────────────┘ + +## Optimization Patterns (Tier 1) + +| Pattern | Detection | Optimization | Verification | +|---------|-----------|-------------|--------------| +| Missing React.memo | Component not wrapped + receives stable props | Wrap with React.memo() | Same render output, fewer renders | +| Missing useMemo | Array .filter/.sort/.map in render body | Wrap computation in useMemo() | Same computed result, fewer executions | +| Missing useCallback | Function defined in render, passed as prop | Wrap with useCallback() | Same behavior, stable reference | +| Inline object props | Object literal in JSX prop position | Extract to useMemo or module constant | Same prop values, stable reference | + +## Extending to Other Frameworks + +To add support for a new framework (e.g., Vue): + +1. Create `languages/javascript/frameworks/vue/` directory +2. Add discovery module: detect Vue SFCs (`.vue` files), `