UNPKG

circuit-bricks

Version:

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

306 lines (304 loc) 7.93 kB
"use strict"; const require_chunk = require('./chunk-OoB0tZi3.cjs'); const require_ssrUtils = require('./ssrUtils-BZC0XRO9.cjs'); const react = require_chunk.__toESM(require("react")); const react_jsx_runtime = require_chunk.__toESM(require("react/jsx-runtime")); //#region src/utils/performanceUtils.tsx /** * Default performance configuration */ const defaultConfig = { enabled: process.env.NODE_ENV === "development", sampleRate: .1, maxSamples: 100, logToConsole: false, trackMemory: true }; /** * Performance monitor class */ var PerformanceMonitor = class { config; samples = []; observers = []; constructor(config = {}) { this.config = { ...defaultConfig, ...config }; } /** * Update configuration */ updateConfig(config) { this.config = { ...this.config, ...config }; } /** * Check if monitoring should occur for this render */ shouldMeasure() { return this.config.enabled && Math.random() < this.config.sampleRate; } /** * Start measuring a render */ startMeasure(label = "circuit-render") { if (!this.shouldMeasure() || !require_ssrUtils.isBrowser()) return () => null; const startTime = performance.now(); const startMemory = this.getMemoryUsage(); return (componentCount = 0, wireCount = 0) => { const endTime = performance.now(); const renderTime = endTime - startTime; const endMemory = this.getMemoryUsage(); const metrics = { renderTime, componentCount, wireCount, memoryUsage: endMemory - startMemory, timestamp: Date.now() }; this.addSample(metrics); return metrics; }; } /** * Get memory usage (if available) */ getMemoryUsage() { if (!this.config.trackMemory || !require_ssrUtils.isBrowser()) return 0; const memory = performance.memory; return memory ? memory.usedJSHeapSize : 0; } /** * Add a performance sample */ addSample(metrics) { this.samples.push(metrics); if (this.samples.length > this.config.maxSamples) this.samples = this.samples.slice(-this.config.maxSamples); if (this.config.logToConsole) console.log("Circuit Performance:", metrics); this.observers.forEach((observer) => observer(metrics)); } /** * Subscribe to performance updates */ subscribe(observer) { this.observers.push(observer); return () => { const index = this.observers.indexOf(observer); if (index > -1) this.observers.splice(index, 1); }; } /** * Get performance statistics */ getStats() { if (this.samples.length === 0) return null; const renderTimes = this.samples.map((s) => s.renderTime); const componentCounts = this.samples.map((s) => s.componentCount); const wireCounts = this.samples.map((s) => s.wireCount); return { sampleCount: this.samples.length, renderTime: { avg: renderTimes.reduce((a, b) => a + b, 0) / renderTimes.length, min: Math.min(...renderTimes), max: Math.max(...renderTimes), p95: this.percentile(renderTimes, .95), p99: this.percentile(renderTimes, .99) }, componentCount: { avg: componentCounts.reduce((a, b) => a + b, 0) / componentCounts.length, min: Math.min(...componentCounts), max: Math.max(...componentCounts) }, wireCount: { avg: wireCounts.reduce((a, b) => a + b, 0) / wireCounts.length, min: Math.min(...wireCounts), max: Math.max(...wireCounts) } }; } /** * Calculate percentile */ percentile(values, p) { const sorted = [...values].sort((a, b) => a - b); const index = Math.ceil(sorted.length * p) - 1; return sorted[index] || 0; } /** * Clear all samples */ clearSamples() { this.samples = []; } /** * Export samples for analysis */ exportSamples() { return [...this.samples]; } }; const globalMonitor = new PerformanceMonitor(); /** * Hook for measuring component render performance */ const useRenderPerformance = (componentName, componentCount = 0, wireCount = 0) => { const measureRef = (0, react.useRef)(null); (0, react.useEffect)(() => { measureRef.current = globalMonitor.startMeasure(`${componentName}-render`); return () => { if (measureRef.current) measureRef.current(componentCount, wireCount); }; }); }; /** * Hook for subscribing to performance metrics */ const usePerformanceMetrics = () => { const [metrics, setMetrics] = (0, react.useState)(null); const [stats, setStats] = (0, react.useState)(globalMonitor.getStats()); (0, react.useEffect)(() => { const unsubscribe = globalMonitor.subscribe((newMetrics) => { setMetrics(newMetrics); setStats(globalMonitor.getStats()); }); return unsubscribe; }, []); const clearMetrics = (0, react.useCallback)(() => { globalMonitor.clearSamples(); setStats(null); }, []); const exportMetrics = (0, react.useCallback)(() => { return globalMonitor.exportSamples(); }, []); return { latestMetrics: metrics, stats, clearMetrics, exportMetrics }; }; /** * Configure global performance monitoring */ const configurePerformanceMonitoring = (config) => { globalMonitor.updateConfig(config); }; /** * Performance-aware component wrapper */ const withPerformanceMonitoring = (Component, componentName) => { return react.default.memo((props) => { useRenderPerformance(componentName); return /* @__PURE__ */ (0, react_jsx_runtime.jsx)( Component, // 0-1, percentage of renders to measure // Maximum number of samples to keep // 10% of renders { ...props } ); }); }; /** * Debounced function utility for performance optimization */ const useDebounce = (func, delay) => { const timeoutRef = (0, react.useRef)(void 0); return (0, react.useCallback)((...args) => { clearTimeout(timeoutRef.current); timeoutRef.current = setTimeout(() => func(...args), delay); }, [func, delay]); }; /** * Throttled function utility for performance optimization */ const useThrottle = (func, delay) => { const lastCallRef = (0, react.useRef)(0); return (0, react.useCallback)((...args) => { const now = Date.now(); if (now - lastCallRef.current >= delay) { lastCallRef.current = now; return func(...args); } }, [func, delay]); }; /** * Frame rate monitor */ const useFrameRate = () => { const [fps, setFps] = (0, react.useState)(60); const frameCountRef = (0, react.useRef)(0); const lastTimeRef = (0, react.useRef)(performance.now()); (0, react.useEffect)(() => { if (!require_ssrUtils.isBrowser()) return; let animationId; const measureFPS = () => { frameCountRef.current++; const currentTime = performance.now(); if (currentTime - lastTimeRef.current >= 1e3) { setFps(frameCountRef.current); frameCountRef.current = 0; lastTimeRef.current = currentTime; } animationId = requestAnimationFrame(measureFPS); }; animationId = requestAnimationFrame(measureFPS); return () => { cancelAnimationFrame(animationId); }; }, []); return fps; }; //#endregion Object.defineProperty(exports, 'configurePerformanceMonitoring', { enumerable: true, get: function () { return configurePerformanceMonitoring; } }); Object.defineProperty(exports, 'globalMonitor', { enumerable: true, get: function () { return globalMonitor; } }); Object.defineProperty(exports, 'useDebounce', { enumerable: true, get: function () { return useDebounce; } }); Object.defineProperty(exports, 'useFrameRate', { enumerable: true, get: function () { return useFrameRate; } }); Object.defineProperty(exports, 'usePerformanceMetrics', { enumerable: true, get: function () { return usePerformanceMetrics; } }); Object.defineProperty(exports, 'useRenderPerformance', { enumerable: true, get: function () { return useRenderPerformance; } }); Object.defineProperty(exports, 'useThrottle', { enumerable: true, get: function () { return useThrottle; } }); Object.defineProperty(exports, 'withPerformanceMonitoring', { enumerable: true, get: function () { return withPerformanceMonitoring; } }); //# sourceMappingURL=performanceUtils-CMrxCxIp.cjs.map