UNPKG

circuit-bricks

Version:

A modular, Lego-style SVG circuit component system for React (ALPHA - Not for production use)

1 lines 13.7 kB
{"version":3,"file":"performanceUtils-CBzmwEek.mjs","names":["defaultConfig: PerformanceConfig","config: Partial<PerformanceConfig>","label: string","componentCount: number","wireCount: number","metrics: PerformanceMetrics","observer: (metrics: PerformanceMetrics) => void","values: number[]","p: number","componentName: string","Component: React.ComponentType<P>","props: P","func: T","delay: number","animationId: number"],"sources":["../../src/utils/performanceUtils.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Performance Monitoring Utilities\n *\n * Utilities for monitoring and optimizing rendering performance in Circuit-Bricks.\n * These tools help track component render times, memory usage, and provide\n * insights for performance optimization.\n */\n\nimport React, { useEffect, useRef, useState, useCallback } from 'react';\nimport { isBrowser } from './ssrUtils';\n\n/**\n * Performance metrics interface\n */\nexport interface PerformanceMetrics {\n renderTime: number;\n componentCount: number;\n wireCount: number;\n memoryUsage?: number;\n timestamp: number;\n}\n\n/**\n * Performance monitoring configuration\n */\nexport interface PerformanceConfig {\n enabled: boolean;\n sampleRate: number; // 0-1, percentage of renders to measure\n maxSamples: number; // Maximum number of samples to keep\n logToConsole: boolean;\n trackMemory: boolean;\n}\n\n/**\n * Default performance configuration\n */\nconst defaultConfig: PerformanceConfig = {\n enabled: process.env.NODE_ENV === 'development',\n sampleRate: 0.1, // 10% of renders\n maxSamples: 100,\n logToConsole: false,\n trackMemory: true\n};\n\n/**\n * Performance monitor class\n */\nclass PerformanceMonitor {\n private config: PerformanceConfig;\n private samples: PerformanceMetrics[] = [];\n private observers: ((metrics: PerformanceMetrics) => void)[] = [];\n\n constructor(config: Partial<PerformanceConfig> = {}) {\n this.config = { ...defaultConfig, ...config };\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<PerformanceConfig>) {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Check if monitoring should occur for this render\n */\n shouldMeasure(): boolean {\n return this.config.enabled && Math.random() < this.config.sampleRate;\n }\n\n /**\n * Start measuring a render\n */\n startMeasure(label: string = 'circuit-render'): () => PerformanceMetrics | null {\n if (!this.shouldMeasure() || !isBrowser()) {\n return () => null;\n }\n\n const startTime = performance.now();\n const startMemory = this.getMemoryUsage();\n\n return (componentCount: number = 0, wireCount: number = 0): PerformanceMetrics | null => {\n const endTime = performance.now();\n const renderTime = endTime - startTime;\n const endMemory = this.getMemoryUsage();\n\n const metrics: PerformanceMetrics = {\n renderTime,\n componentCount,\n wireCount,\n memoryUsage: endMemory - startMemory,\n timestamp: Date.now()\n };\n\n this.addSample(metrics);\n return metrics;\n };\n }\n\n /**\n * Get memory usage (if available)\n */\n private getMemoryUsage(): number {\n if (!this.config.trackMemory || !isBrowser()) return 0;\n\n // @ts-ignore - performance.memory is not in all browsers\n const memory = (performance as any).memory;\n return memory ? memory.usedJSHeapSize : 0;\n }\n\n /**\n * Add a performance sample\n */\n private addSample(metrics: PerformanceMetrics) {\n this.samples.push(metrics);\n\n // Keep only the most recent samples\n if (this.samples.length > this.config.maxSamples) {\n this.samples = this.samples.slice(-this.config.maxSamples);\n }\n\n // Log to console if enabled\n if (this.config.logToConsole) {\n console.log('Circuit Performance:', metrics);\n }\n\n // Notify observers\n this.observers.forEach(observer => observer(metrics));\n }\n\n /**\n * Subscribe to performance updates\n */\n subscribe(observer: (metrics: PerformanceMetrics) => void): () => void {\n this.observers.push(observer);\n return () => {\n const index = this.observers.indexOf(observer);\n if (index > -1) {\n this.observers.splice(index, 1);\n }\n };\n }\n\n /**\n * Get performance statistics\n */\n getStats() {\n if (this.samples.length === 0) {\n return null;\n }\n\n const renderTimes = this.samples.map(s => s.renderTime);\n const componentCounts = this.samples.map(s => s.componentCount);\n const wireCounts = this.samples.map(s => s.wireCount);\n\n return {\n sampleCount: this.samples.length,\n renderTime: {\n avg: renderTimes.reduce((a, b) => a + b, 0) / renderTimes.length,\n min: Math.min(...renderTimes),\n max: Math.max(...renderTimes),\n p95: this.percentile(renderTimes, 0.95),\n p99: this.percentile(renderTimes, 0.99)\n },\n componentCount: {\n avg: componentCounts.reduce((a, b) => a + b, 0) / componentCounts.length,\n min: Math.min(...componentCounts),\n max: Math.max(...componentCounts)\n },\n wireCount: {\n avg: wireCounts.reduce((a, b) => a + b, 0) / wireCounts.length,\n min: Math.min(...wireCounts),\n max: Math.max(...wireCounts)\n }\n };\n }\n\n /**\n * Calculate percentile\n */\n private percentile(values: number[], p: number): number {\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil(sorted.length * p) - 1;\n return sorted[index] || 0;\n }\n\n /**\n * Clear all samples\n */\n clearSamples() {\n this.samples = [];\n }\n\n /**\n * Export samples for analysis\n */\n exportSamples() {\n return [...this.samples];\n }\n}\n\n// Global performance monitor instance\nconst globalMonitor = new PerformanceMonitor();\n\n/**\n * Hook for measuring component render performance\n */\nexport const useRenderPerformance = (\n componentName: string,\n componentCount: number = 0,\n wireCount: number = 0\n) => {\n const measureRef = useRef<((componentCount?: number, wireCount?: number) => PerformanceMetrics | null) | null>(null);\n\n useEffect(() => {\n // Start measuring at the beginning of render\n measureRef.current = globalMonitor.startMeasure(`${componentName}-render`);\n\n // Finish measuring after render is complete\n return () => {\n if (measureRef.current) {\n measureRef.current(componentCount, wireCount);\n }\n };\n });\n};\n\n/**\n * Hook for subscribing to performance metrics\n */\nexport const usePerformanceMetrics = () => {\n const [metrics, setMetrics] = useState<PerformanceMetrics | null>(null);\n const [stats, setStats] = useState(globalMonitor.getStats());\n\n useEffect(() => {\n const unsubscribe = globalMonitor.subscribe((newMetrics) => {\n setMetrics(newMetrics);\n setStats(globalMonitor.getStats());\n });\n\n return unsubscribe;\n }, []);\n\n const clearMetrics = useCallback(() => {\n globalMonitor.clearSamples();\n setStats(null);\n }, []);\n\n const exportMetrics = useCallback(() => {\n return globalMonitor.exportSamples();\n }, []);\n\n return {\n latestMetrics: metrics,\n stats,\n clearMetrics,\n exportMetrics\n };\n};\n\n/**\n * Configure global performance monitoring\n */\nexport const configurePerformanceMonitoring = (config: Partial<PerformanceConfig>) => {\n globalMonitor.updateConfig(config);\n};\n\n/**\n * Performance-aware component wrapper\n */\nexport const withPerformanceMonitoring = <P extends object>(\n Component: React.ComponentType<P>,\n componentName: string\n) => {\n return React.memo((props: P) => {\n useRenderPerformance(componentName);\n return <Component {...props} />;\n });\n};\n\n/**\n * Debounced function utility for performance optimization\n */\nexport const useDebounce = <T extends (...args: any[]) => any>(\n func: T,\n delay: number\n): T => {\n const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);\n\n return useCallback(\n ((...args: Parameters<T>) => {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => func(...args), delay);\n }) as T,\n [func, delay]\n );\n};\n\n/**\n * Throttled function utility for performance optimization\n */\nexport const useThrottle = <T extends (...args: any[]) => any>(\n func: T,\n delay: number\n): T => {\n const lastCallRef = useRef<number>(0);\n\n return useCallback(\n ((...args: Parameters<T>) => {\n const now = Date.now();\n if (now - lastCallRef.current >= delay) {\n lastCallRef.current = now;\n return func(...args);\n }\n }) as T,\n [func, delay]\n );\n};\n\n/**\n * Frame rate monitor\n */\nexport const useFrameRate = () => {\n const [fps, setFps] = useState(60);\n const frameCountRef = useRef(0);\n const lastTimeRef = useRef(performance.now());\n\n useEffect(() => {\n if (!isBrowser()) return;\n\n let animationId: number;\n\n const measureFPS = () => {\n frameCountRef.current++;\n const currentTime = performance.now();\n\n if (currentTime - lastTimeRef.current >= 1000) {\n setFps(frameCountRef.current);\n frameCountRef.current = 0;\n lastTimeRef.current = currentTime;\n }\n\n animationId = requestAnimationFrame(measureFPS);\n };\n\n animationId = requestAnimationFrame(measureFPS);\n\n return () => {\n cancelAnimationFrame(animationId);\n };\n }, []);\n\n return fps;\n};\n\nexport { globalMonitor as performanceMonitor };\n"],"mappings":"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"}