/ utils / performance.ts
performance.ts
  1  // Performance monitoring utilities
  2  
  3  interface PerformanceMetric {
  4    name: string;
  5    startTime: number;
  6    endTime?: number;
  7    duration?: number;
  8  }
  9  
 10  class PerformanceMonitor {
 11    private static instance: PerformanceMonitor;
 12    private metrics: Map<string, PerformanceMetric> = new Map();
 13    private isEnabled: boolean = __DEV__; // Only enable in development
 14  
 15    private constructor() {}
 16  
 17    static getInstance(): PerformanceMonitor {
 18      if (!PerformanceMonitor.instance) {
 19        PerformanceMonitor.instance = new PerformanceMonitor();
 20      }
 21      return PerformanceMonitor.instance;
 22    }
 23  
 24    startMeasure(name: string): void {
 25      if (!this.isEnabled) return;
 26  
 27      this.metrics.set(name, {
 28        name,
 29        startTime: performance.now(),
 30      });
 31    }
 32  
 33    endMeasure(name: string): number | null {
 34      if (!this.isEnabled) return null;
 35  
 36      const metric = this.metrics.get(name);
 37      if (!metric) {
 38        console.warn(`Performance metric "${name}" was not started`);
 39        return null;
 40      }
 41  
 42      const endTime = performance.now();
 43      const duration = endTime - metric.startTime;
 44  
 45      metric.endTime = endTime;
 46      metric.duration = duration;
 47  
 48      if (duration > 100) {
 49        // Log slow operations (>100ms)
 50        console.log(`[Performance] ${name}: ${duration.toFixed(2)}ms`);
 51      }
 52  
 53      return duration;
 54    }
 55  
 56    measureAsync<T>(name: string, operation: () => Promise<T>): Promise<T> {
 57      if (!this.isEnabled) return operation();
 58  
 59      this.startMeasure(name);
 60      return operation().finally(() => {
 61        this.endMeasure(name);
 62      });
 63    }
 64  
 65    measureSync<T>(name: string, operation: () => T): T {
 66      if (!this.isEnabled) return operation();
 67  
 68      this.startMeasure(name);
 69      try {
 70        return operation();
 71      } finally {
 72        this.endMeasure(name);
 73      }
 74    }
 75  
 76    getMetrics(): PerformanceMetric[] {
 77      return Array.from(this.metrics.values());
 78    }
 79  
 80    clearMetrics(): void {
 81      this.metrics.clear();
 82    }
 83  
 84    enable(): void {
 85      this.isEnabled = true;
 86    }
 87  
 88    disable(): void {
 89      this.isEnabled = false;
 90    }
 91  }
 92  
 93  export const performanceMonitor = PerformanceMonitor.getInstance();
 94  
 95  // React hook for measuring component render times
 96  export function useRenderTime(componentName: string) {
 97    if (__DEV__) {
 98      performanceMonitor.startMeasure(`render:${componentName}`);
 99  
100      return () => {
101        performanceMonitor.endMeasure(`render:${componentName}`);
102      };
103    }
104  
105    return () => {}; // No-op in production
106  }
107  
108  // Decorator for measuring function execution time
109  export function measureExecutionTime(
110    target: any,
111    propertyName: string,
112    descriptor: PropertyDescriptor
113  ) {
114    if (!__DEV__) return descriptor;
115  
116    const method = descriptor.value;
117  
118    descriptor.value = function (...args: any[]) {
119      const functionName = `${target.constructor.name}.${propertyName}`;
120      return performanceMonitor.measureSync(functionName, () =>
121        method.apply(this, args)
122      );
123    };
124  
125    return descriptor;
126  }
127  
128  // Utility for measuring component lifecycle
129  export function measureComponentLifecycle(ComponentClass: any) {
130    if (!__DEV__) return ComponentClass;
131  
132    const originalRender = ComponentClass.prototype.render;
133    const componentName = ComponentClass.name;
134  
135    ComponentClass.prototype.render = function () {
136      const endMeasure = useRenderTime(componentName);
137      const result = originalRender.call(this);
138      endMeasure();
139      return result;
140    };
141  
142    return ComponentClass;
143  }
144  
145  export default performanceMonitor;