Architecture
Internal architecture and design patterns for contributors.
System Overview
React Performance Tracking is a two-layer library for automated performance testing:
| Layer | Purpose | Entry Point | Runtime |
|---|---|---|---|
| React | Client-side profiling | react-performance-tracking/react | Browser |
| Playwright | Test orchestration | react-performance-tracking/playwright | Node.js |
Component Structure
┌───────────────────────────────────────────────────────────────────────┐
│ Consumer Application │
├──────────────────────────────────┬────────────────────────────────────┤
│ React Layer │ Playwright Layer │
│ ┌────────────────────────┐ │ ┌───────────────────────┐ │
│ │ PerformanceProvider │ │ │ createPerformanceTest │ │
│ │ + Context │ │ │ + test.performance │ │
│ └───────────┬────────────┘ │ └───────────┬───────────┘ │
│ │ │ │ │
│ ┌───────────▼────────────┐ │ ┌───────────▼───────────┐ │
│ │ usePerformance │ │ │PerformanceTestRunner │ │
│ │ usePerformanceStore │ │ │ (orchestration) │ │
│ └───────────┬────────────┘ │ └───────────┬───────────┘ │
│ │ │ │ │
│ ┌───────────▼────────────┐ │ ┌───────────▼───────────┐ │
│ │ window.__REACT_ │◄─────┼──────│ captureProfilerState │ │
│ │ PERFORMANCE__ │ │ │ │ │
│ └────────────────────────┘ │ └───────────────────────┘ │
│ │ │ │
│ │ ┌───────────▼───────────┐ │
│ │ │ CDP Feature System │ │
│ │ │ (Chromium only) │ │
│ │ └───────────────────────┘ │
└──────────────────────────────────┴────────────────────────────────────┘Plugin Architecture (CDP Features)
All Chrome DevTools Protocol features use a unified plugin system:
interface CDPFeature<TConfig = void, TMetrics = void> {
readonly name: string;
readonly requiresChromium: boolean;
start(page: Page, config: TConfig): Promise<CDPFeatureHandle<TMetrics> | null>;
}
interface CDPFeatureHandle<TMetrics = void> {
stop(): Promise<TMetrics | null>;
isActive(): boolean;
}
interface ResettableCDPFeatureHandle<TMetrics> extends CDPFeatureHandle<TMetrics> {
reset(): Promise<void>;
}Registry Pattern
Features self-register with a central registry for lifecycle management:
// Feature registration
featureRegistry.register(cpuThrottlingFeature);
featureRegistry.register(networkThrottlingFeature);
featureRegistry.register(fpsTrackingFeature);
featureRegistry.register(memoryTrackingFeature);
// Lifecycle management
const handle = await featureRegistry.startFeature('cpu-throttling', page, config);
await featureRegistry.stopAll(handles);React Layer Components
| Component | Responsibility |
|---|---|
PerformanceProvider | Context provider exposing profiler callback |
usePerformance | Hook returning onProfilerRender (nullable outside provider) |
usePerformanceRequired | Hook that throws if used outside provider |
usePerformanceStore | Internal hook managing global store lifecycle |
Playwright Layer Components
| Component | Responsibility |
|---|---|
createPerformanceTest | Factory extending Playwright test with test.performance() |
PerformanceTestRunner | Orchestrates test execution, features, assertions |
performanceFixture | Standalone fixture for custom test setups |
captureProfilerState | Captures React metrics from browser via page.evaluate() |
CDP Feature Implementations
| Feature | CDP APIs Used | Metrics |
|---|---|---|
cpuThrottlingFeature | Emulation.setCPUThrottlingRate | None |
networkThrottlingFeature | Network.emulateNetworkConditions | None |
fpsTrackingFeature | Tracing API | avg, frameCount, trackingDurationMs |
memoryTrackingFeature | Performance.getMetrics | heapGrowth, heapGrowthPercent |
traceExportFeature | Tracing API | Trace file path |
Data Flow
Initialization Phase
test.performance()createsConfiguredTestInfowith resolved thresholdsPerformanceTestRunnerstarts CDP features (if Chromium)- Test navigates to page with
PerformanceProvider performance.init()waits forwindow.__REACT_PERFORMANCE__and stability
Collection Phase
- React's
<Profiler>callsonProfilerRenderon each render - Samples are stored in
window.__REACT_PERFORMANCE__.samples - Per-component aggregations update in
components
Assertion Phase
PerformanceTestRunnercaptures final state viapage.evaluate()- Thresholds are validated with buffers applied
- Test fails with clear error if threshold exceeded
- Artifacts are attached to test report
Design Principles
- Graceful Degradation – CDP features skip on non-Chromium without errors
- Zero Runtime Dependencies – No external packages in React layer
- Type Safety – Full TypeScript with strict mode
- Minimal API Surface – Simple defaults, advanced escape hatches
- Clear Error Messages – Actionable feedback on failures
Integration Patterns
Cross-Boundary Communication
React-to-Playwright communication via window global:
// React side (runs in browser)
window.__REACT_PERFORMANCE__ = store;
// Playwright side (runs in Node.js)
const metrics = await page.evaluate(() => window.__REACT_PERFORMANCE__);Feature Lifecycle
All CDP features follow the same lifecycle pattern:
// 1. Start (returns handle)
const handle = await feature.start(page, config);
// 2. Reset (optional, for iterations)
await handle.reset?.();
// 3. Stop (returns metrics and cleans up)
const metrics = await handle.stop();Security Architecture
| Concern | Mitigation |
|---|---|
| CDP Session Leaks | Sessions detached in finally blocks via detachCDPSession() |
| Sensitive Data | No user data in window globals or artifacts |
| Trace Files | Local-only, not transmitted externally |
| Dependency Injection | No dynamic code execution or eval |
| Error Information | Stack traces not exposed to end users |
Safe Cleanup Pattern
try {
// ... feature operation
} finally {
await detachCDPSession(session);
}
// Or with safeCDPSend for non-critical cleanup
await safeCDPSend(session, 'Method', params); // Silent on failureRelated
- Custom Fixtures – Extending functionality
- Testing Guidelines – Unit test patterns