UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

261 lines (258 loc) 7.67 kB
'use client'; import { useState, useRef, useCallback, useEffect } from 'react'; const defaultMetrics = { cls: 0, fcp: 0, lcp: 0, fid: 0, inp: 0, fps: 60, memoryUsage: 0, domElements: 0, networkLatency: 0, bundleSize: 0, timeToInteractive: 0, totalBlockingTime: 0 }; const defaultSettings = { enableMonitoring: true, sampleRate: 100, // Monitor 100% in development reportingInterval: 5000, // Report every 5 seconds enableDevtools: process.env.NODE_ENV === 'development' }; const usePerformance = (settings = {}) => { const [metrics, setMetrics] = useState(defaultMetrics); const [isMonitoring, setIsMonitoring] = useState(false); const [alerts, setAlerts] = useState([]); const config = { ...defaultSettings, ...settings }; const frameId = useRef(); const lastFrameTime = useRef(performance.now()); const frameCount = useRef(0); // FPS monitoring const measureFPS = useCallback(() => { const now = performance.now(); frameCount.current++; if (now - lastFrameTime.current >= 1000) { const fps = Math.round(frameCount.current * 1000 / (now - lastFrameTime.current)); setMetrics(prev => ({ ...prev, fps })); frameCount.current = 0; lastFrameTime.current = now; // Alert on low FPS if (fps < 30) { setAlerts(prev => [...prev, `Low FPS detected: ${fps}`]); } } if (isMonitoring) { frameId.current = requestAnimationFrame(measureFPS); } }, [isMonitoring]); // Memory usage monitoring const measureMemoryUsage = useCallback(() => { if ('memory' in performance) { const memory = performance.memory; const memoryUsage = Math.round(memory.usedJSHeapSize / 1024 / 1024); setMetrics(prev => ({ ...prev, memoryUsage })); // Alert on high memory usage if (memoryUsage > 100) { setAlerts(prev => [...prev, `High memory usage: ${memoryUsage}MB`]); } } }, []); // DOM elements count const measureDOMComplexity = useCallback(() => { const domElements = document.querySelectorAll('*').length; setMetrics(prev => ({ ...prev, domElements })); // Alert on DOM complexity if (domElements > 2000) { setAlerts(prev => [...prev, `High DOM complexity: ${domElements} elements`]); } }, []); // Web Vitals monitoring const measureWebVitals = useCallback(() => { // Use Web Vitals library if available if ('webVitals' in window) { return; } // Basic CLS measurement let clsValue = 0; const observer = new PerformanceObserver(list => { for (const entry of list.getEntries()) { if (entry.entryType === 'layout-shift' && !entry.hadRecentInput) { clsValue += entry.value; } } setMetrics(prev => ({ ...prev, cls: clsValue })); }); try { observer.observe({ type: 'layout-shift', buffered: true }); } catch (e) { // Layout shift not supported } // LCP measurement const lcpObserver = new PerformanceObserver(list => { const entries = list.getEntries(); const lastEntry = entries[entries.length - 1]; setMetrics(prev => ({ ...prev, lcp: lastEntry.startTime })); }); try { lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true }); } catch (e) { // LCP not supported } return () => { observer.disconnect(); lcpObserver.disconnect(); }; }, []); // Network latency estimation const measureNetworkLatency = useCallback(async () => { const start = performance.now(); try { await fetch('/favicon.ico', { method: 'HEAD' }); const latency = performance.now() - start; setMetrics(prev => ({ ...prev, networkLatency: Math.round(latency) })); } catch (e) { // Network request failed } }, []); // Start monitoring const startMonitoring = useCallback(() => { if (Math.random() * 100 > config.sampleRate) return; setIsMonitoring(true); measureFPS(); const interval = setInterval(() => { measureMemoryUsage(); measureDOMComplexity(); measureNetworkLatency(); }, config.reportingInterval); const cleanup = measureWebVitals(); return () => { setIsMonitoring(false); clearInterval(interval); if (frameId.current) { cancelAnimationFrame(frameId.current); } cleanup?.(); }; }, [config.sampleRate, config.reportingInterval, measureFPS, measureMemoryUsage, measureDOMComplexity, measureNetworkLatency, measureWebVitals]); // Stop monitoring const stopMonitoring = useCallback(() => { setIsMonitoring(false); if (frameId.current) { cancelAnimationFrame(frameId.current); } }, []); // Performance recommendations const getRecommendations = useCallback(() => { const recommendations = []; if (metrics.fps < 30) { recommendations.push('Consider reducing animations or using will-change CSS property'); } if (metrics.memoryUsage > 100) { recommendations.push('High memory usage detected. Check for memory leaks'); } if (metrics.domElements > 2000) { recommendations.push('High DOM complexity. Consider virtualizing long lists'); } if (metrics.cls > 0.1) { recommendations.push('Layout shifts detected. Ensure elements have defined dimensions'); } if (metrics.lcp > 2500) { recommendations.push('Slow loading detected. Optimize images and critical resources'); } if (metrics.networkLatency > 200) { recommendations.push('High network latency. Consider caching or CDN optimization'); } return recommendations; }, [metrics]); // Performance score calculation const getPerformanceScore = useCallback(() => { let score = 100; // FPS penalty if (metrics.fps < 60) score -= (60 - metrics.fps) * 0.5; // Memory penalty if (metrics.memoryUsage > 50) score -= (metrics.memoryUsage - 50) * 0.2; // DOM complexity penalty if (metrics.domElements > 1000) score -= (metrics.domElements - 1000) * 0.01; // Web Vitals penalties if (metrics.cls > 0.1) score -= metrics.cls * 100; if (metrics.lcp > 2500) score -= (metrics.lcp - 2500) * 0.01; return Math.max(0, Math.round(score)); }, [metrics]); // Clear alerts const clearAlerts = useCallback(() => { setAlerts([]); }, []); // Export metrics for reporting const exportMetrics = useCallback(() => { return { ...metrics, timestamp: Date.now(), userAgent: navigator.userAgent, url: window.location.href, performanceScore: getPerformanceScore(), recommendations: getRecommendations() }; }, [metrics, getPerformanceScore, getRecommendations]); // Initialize monitoring on mount useEffect(() => { if (!config.enableMonitoring) return; const cleanup = startMonitoring(); return cleanup; }, [config.enableMonitoring, startMonitoring]); // Performance grade const getGrade = useCallback(() => { const score = getPerformanceScore(); if (score >= 90) return 'A'; if (score >= 80) return 'B'; if (score >= 70) return 'C'; if (score >= 60) return 'D'; return 'F'; }, [getPerformanceScore]); return { metrics, isMonitoring, alerts, startMonitoring, stopMonitoring, getRecommendations, getPerformanceScore, getGrade, clearAlerts, exportMetrics, config }; }; export { usePerformance }; //# sourceMappingURL=usePerformance.js.map