aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
261 lines (258 loc) • 7.67 kB
JavaScript
'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