UNPKG

aura-glass

Version:

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

387 lines (384 loc) 11.2 kB
import { canUseDOM } from './ssr.js'; // Performance monitoring class PerformanceMonitor { constructor(config = {}) { this.observers = []; this.frameCount = 0; this.lastTime = 0; this.measurements = new Map(); this.config = { enableFPSMonitoring: true, enableMemoryMonitoring: false, enableNetworkMonitoring: false, targetFPS: 60, maxMemoryUsage: 100 * 1024 * 1024, // 100MB enableAdaptiveQuality: true, enableVirtualization: true, enableLazyLoading: true, enableCaching: true, enableCompression: false, ...config }; this.metrics = { fps: 0, frameTime: 0, memoryUsage: 0, renderTime: 0, layoutTime: 0, paintTime: 0, compositeTime: 0, networkLatency: 0, cacheHitRate: 0 }; this.initializeMonitoring(); } static getInstance(config) { if (!PerformanceMonitor.instance) { PerformanceMonitor.instance = new PerformanceMonitor(config); } return PerformanceMonitor.instance; } initializeMonitoring() { // Skip monitoring during SSR if (!canUseDOM) return; if (this.config.enableFPSMonitoring) { this.startFPSMonitoring(); } if (this.config.enableMemoryMonitoring && "memory" in performance) { this.startMemoryMonitoring(); } if (this.config.enableNetworkMonitoring) { this.startNetworkMonitoring(); } } startFPSMonitoring() { const measureFPS = timestamp => { this.frameCount++; if (this.lastTime === 0) { this.lastTime = timestamp; requestAnimationFrame(measureFPS); return; } const deltaTime = timestamp - this.lastTime; if (deltaTime >= 1000) { // Update every second this.metrics.fps = Math.round(this.frameCount * 1000 / deltaTime); this.metrics.frameTime = deltaTime / this.frameCount; this.frameCount = 0; this.lastTime = timestamp; } requestAnimationFrame(measureFPS); }; requestAnimationFrame(measureFPS); } startMemoryMonitoring() { setInterval(() => { const memory = performance.memory; if (memory) { this.metrics.memoryUsage = memory.usedJSHeapSize; } }, 5000); // Check every 5 seconds } startNetworkMonitoring() { // Skip during SSR - no fetch API available if (!canUseDOM) return; // Monitor fetch requests const originalFetch = window.fetch; let requestCount = 0; let cacheHits = 0; window.fetch = async (...args) => { const startTime = Date.now(); requestCount++; try { const response = await originalFetch(...args); const duration = Date.now() - startTime; // Estimate cache hit based on response time if (duration < 50) { cacheHits++; } this.metrics.networkLatency = duration; this.metrics.cacheHitRate = cacheHits / requestCount * 100; return response; } catch (error) { throw error; } }; } getMetrics() { return { ...this.metrics }; } isPerformanceGood() { return this.metrics.fps >= this.config.targetFPS * 0.8 && this.metrics.memoryUsage <= this.config.maxMemoryUsage; } getOptimizationSuggestions() { const suggestions = []; if (this.metrics.fps < this.config.targetFPS * 0.8) { suggestions.push("Consider reducing animation complexity"); suggestions.push("Enable virtualization for large lists"); suggestions.push("Reduce particle effects or simplify shaders"); } if (this.metrics.memoryUsage > this.config.maxMemoryUsage * 0.8) { suggestions.push("Implement memory cleanup"); suggestions.push("Reduce texture sizes"); suggestions.push("Unload unused assets"); } if (this.metrics.renderTime > 16.67) { // 60 FPS threshold suggestions.push("Optimize render pipeline"); suggestions.push("Use CSS transforms instead of layout properties"); suggestions.push("Implement object pooling"); } return suggestions; } startMeasure(name) { this.measurements.set(name, { startTime: performance.now() }); } stop() { // Stop all measurements and log results for (const [name, measurement] of this.measurements) { if (!measurement.endTime) { measurement.endTime = performance.now(); const duration = measurement.endTime - measurement.startTime; console.log(`Performance measurement '${name}': ${duration.toFixed(2)}ms`); } } this.measurements.clear(); } getMeasurementDuration(name) { const measurement = this.measurements.get(name); if (measurement && measurement.endTime) { return measurement.endTime - measurement.startTime; } return null; } } // Memory management class MemoryManager { constructor(maxCacheSize = 50 * 1024 * 1024) { this.cache = new Map(); this.currentCacheSize = 0; // 50MB default this.maxCacheSize = maxCacheSize; } static getInstance(maxCacheSize) { if (!MemoryManager.instance) { MemoryManager.instance = new MemoryManager(maxCacheSize); } return MemoryManager.instance; } set(key, value, size = 0) { if (this.currentCacheSize + size > this.maxCacheSize) { this.evictOldEntries(size); } this.cache.set(key, { value, size, lastAccessed: Date.now() }); this.currentCacheSize += size; } get(key) { const entry = this.cache.get(key); if (entry) { entry.lastAccessed = Date.now(); return entry.value; } return null; } delete(key) { const entry = this.cache.get(key); if (entry) { this.currentCacheSize -= entry.size; return this.cache.delete(key); } return false; } clear() { this.cache.clear(); this.currentCacheSize = 0; } evictOldEntries(requiredSize) { const entries = Array.from(this.cache.entries()).sort((a, b) => a[1].lastAccessed - b[1].lastAccessed); let freedSize = 0; for (const [key, entry] of entries) { if (freedSize >= requiredSize) break; freedSize += entry.size; this.cache.delete(key); } this.currentCacheSize -= freedSize; } getStats() { return { size: this.currentCacheSize, entries: this.cache.size, hitRate: 0 // Would need to track hits/misses }; } } // Rendering optimizations const renderingOptimizations = { // Use transform instead of changing layout properties useTransformForMovement: (element, x, y) => { element.style.transform = `translate(${x}px, ${y}px)`; element.style.willChange = "transform"; }, // Optimize for 60fps animations optimizeFor60FPS: callback => { let lastTime = 0; const animate = timestamp => { if (timestamp - lastTime >= 16.67) { // ~60fps callback(); lastTime = timestamp; } requestAnimationFrame(animate); }; requestAnimationFrame(animate); }, // Batch DOM updates batchDOMUpdates: updates => { requestAnimationFrame(() => { updates.forEach(update => update()); }); }, // Use CSS containment for performance enableCSSContainment: element => { element.style.contain = "layout style paint"; }, // Optimize canvas rendering optimizeCanvasRendering: canvas => { const ctx = canvas.getContext("2d"); if (ctx) { ctx.imageSmoothingEnabled = false; ctx.globalCompositeOperation = "source-over"; } } }; // Network optimizations const networkOptimizations = { // Lazy load images lazyLoadImage: (img, src) => { const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { img.src = src; observer.disconnect(); } }); }); observer.observe(img); }, // Preload critical resources preloadCriticalResources: resources => { // Skip during SSR - no document API available if (!canUseDOM) return; resources.forEach(resource => { const link = document.createElement("link"); link.rel = "preload"; link.href = resource; document.head.appendChild(link); }); }, // Cache API wrapper cacheAPI: { async set(key, data) { if ("caches" in window) { const cache = await caches.open("glass-cache-v1"); await cache.put(key, new Response(JSON.stringify(data))); } }, async get(key) { if ("caches" in window) { const cache = await caches.open("glass-cache-v1"); const response = await cache.match(key); if (response) { return response.json(); } } return null; } } }; // Virtualization utilities class VirtualScroller { constructor(container, itemHeight, totalItems, visibleItems) { this.scrollTop = 0; this.container = container; this.itemHeight = itemHeight; this.totalItems = totalItems; this.visibleItems = visibleItems; this.setupEventListeners(); } setupEventListeners() { this.container.addEventListener("scroll", this.handleScroll.bind(this)); } handleScroll() { this.scrollTop = this.container.scrollTop; this.updateVisibleItems(); } updateVisibleItems() { const startIndex = Math.floor(this.scrollTop / this.itemHeight); const endIndex = Math.min(startIndex + this.visibleItems, this.totalItems); // Dispatch custom event with visible range const event = new CustomEvent("virtualScroll", { detail: { startIndex, endIndex } }); this.container.dispatchEvent(event); } getVisibleRange() { const start = Math.floor(this.scrollTop / this.itemHeight); const end = Math.min(start + this.visibleItems, this.totalItems); return { start, end }; } scrollToItem(index) { this.container.scrollTop = index * this.itemHeight; } } // Adaptive quality system class AdaptiveQuality { constructor(monitor) { this.qualityLevel = 1.0; this.monitor = monitor; } updateQuality() { const metrics = this.monitor.getMetrics(); const targetFPS = 60; const fpsRatio = metrics.fps / targetFPS; if (fpsRatio < 0.8) { // Reduce quality this.qualityLevel = Math.max(0.1, this.qualityLevel * 0.9); } else if (fpsRatio > 1.2) { // Increase quality this.qualityLevel = Math.min(1.0, this.qualityLevel * 1.05); } return this.qualityLevel; } getQualitySettings() { return { particleCount: Math.floor(1000 * this.qualityLevel), textureSize: Math.floor(1024 * this.qualityLevel), shadowQuality: Math.floor(4 * this.qualityLevel), antialiasing: this.qualityLevel > 0.5 }; } } // Export utilities const performanceUtils = { monitor: PerformanceMonitor.getInstance, memory: MemoryManager.getInstance, adaptiveQuality: monitor => new AdaptiveQuality(monitor), virtualScroller: VirtualScroller }; export { AdaptiveQuality, MemoryManager, PerformanceMonitor, VirtualScroller, networkOptimizations, performanceUtils, renderingOptimizations }; //# sourceMappingURL=performanceOptimizations.js.map