UNPKG

@sc4rfurryx/proteusjs

Version:

The Modern Web Development Framework for Accessible, Responsive, and High-Performance Applications. Intelligent container queries, fluid typography, WCAG compliance, and performance optimization.

258 lines (256 loc) 8.44 kB
/*! * ProteusJS v2.0.0 * Shape-shifting responsive design that adapts like the sea god himself * (c) 2025 sc4rfurry * Released under the MIT License */ /** * @sc4rfurryx/proteusjs/perf * Performance guardrails and CWV-friendly patterns * * @version 2.0.0 * @author sc4rfurry * @license MIT */ /** * Apply content-visibility for performance optimization */ function contentVisibility(selector, mode = 'auto', opts = {}) { const elements = typeof selector === 'string' ? document.querySelectorAll(selector) : [selector]; const { containIntrinsicSize = '1000px 400px' } = opts; elements.forEach(element => { const el = element; el.style.contentVisibility = mode; if (mode === 'auto') { el.style.containIntrinsicSize = containIntrinsicSize; } }); } /** * Set fetch priority for resources */ function fetchPriority(selector, priority) { const elements = typeof selector === 'string' ? document.querySelectorAll(selector) : [selector]; elements.forEach(element => { if (element instanceof HTMLImageElement || element instanceof HTMLLinkElement || element instanceof HTMLScriptElement) { element.fetchPriority = priority; } }); } /** * Set up speculation rules for prerendering and prefetching */ function speculate(opts) { const { prerender = [], prefetch = [], sameOriginOnly = true } = opts; // Check for Speculation Rules API support if (!('supports' in HTMLScriptElement && HTMLScriptElement.supports('speculationrules'))) { console.warn('Speculation Rules API not supported'); return; } const rules = {}; if (prerender.length > 0) { rules.prerender = prerender.map(url => { const rule = { where: { href_matches: url } }; if (sameOriginOnly) { rule.where.href_matches = new URL(url, window.location.origin).href; } return rule; }); } if (prefetch.length > 0) { rules.prefetch = prefetch.map(url => { const rule = { where: { href_matches: url } }; if (sameOriginOnly) { rule.where.href_matches = new URL(url, window.location.origin).href; } return rule; }); } if (Object.keys(rules).length === 0) return; // Create and inject speculation rules script const script = document.createElement('script'); script.type = 'speculationrules'; script.textContent = JSON.stringify(rules); document.head.appendChild(script); } /** * Yield to browser using scheduler.yield or postTask when available */ async function yieldToBrowser() { // Use scheduler.yield if available (Chrome 115+) if ('scheduler' in window && 'yield' in window.scheduler) { return window.scheduler.yield(); } // Use scheduler.postTask if available if ('scheduler' in window && 'postTask' in window.scheduler) { return new Promise(resolve => { window.scheduler.postTask(resolve, { priority: 'user-blocking' }); }); } // Fallback to setTimeout return new Promise(resolve => { setTimeout(resolve, 0); }); } /** * Optimize images with loading and decoding hints */ function optimizeImages(selector = 'img') { const images = typeof selector === 'string' ? document.querySelectorAll(selector) : [selector]; images.forEach(img => { if (!(img instanceof HTMLImageElement)) return; // Set loading attribute if not already set if (!img.hasAttribute('loading')) { const rect = img.getBoundingClientRect(); const isAboveFold = rect.top < window.innerHeight; img.loading = isAboveFold ? 'eager' : 'lazy'; } // Set decoding hint if (!img.hasAttribute('decoding')) { img.decoding = 'async'; } // Set fetch priority for above-fold images if (!img.hasAttribute('fetchpriority')) { const rect = img.getBoundingClientRect(); const isAboveFold = rect.top < window.innerHeight; if (isAboveFold) { img.fetchPriority = 'high'; } } }); } /** * Preload critical resources */ function preloadCritical(resources) { resources.forEach(({ href, as, type }) => { // Check if already preloaded const existing = document.querySelector(`link[rel="preload"][href="${href}"]`); if (existing) return; const link = document.createElement('link'); link.rel = 'preload'; link.href = href; link.as = as; if (type) { link.type = type; } document.head.appendChild(link); }); } /** * Measure and report Core Web Vitals */ function measureCWV() { return new Promise(resolve => { const metrics = {}; let metricsCount = 0; const totalMetrics = 3; const checkComplete = () => { metricsCount++; if (metricsCount >= totalMetrics) { resolve(metrics); } }; // LCP (Largest Contentful Paint) if ('PerformanceObserver' in window) { try { const lcpObserver = new PerformanceObserver(list => { const entries = list.getEntries(); const lastEntry = entries[entries.length - 1]; metrics.lcp = lastEntry.startTime; }); lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] }); // Stop observing after 10 seconds setTimeout(() => { lcpObserver.disconnect(); checkComplete(); }, 10000); } catch { checkComplete(); } // FID (First Input Delay) try { const fidObserver = new PerformanceObserver(list => { const entries = list.getEntries(); entries.forEach((entry) => { metrics.fid = entry.processingStart - entry.startTime; }); fidObserver.disconnect(); checkComplete(); }); fidObserver.observe({ entryTypes: ['first-input'] }); // If no input after 10 seconds, consider FID as 0 setTimeout(() => { if (metrics.fid === undefined) { metrics.fid = 0; fidObserver.disconnect(); checkComplete(); } }, 10000); } catch { checkComplete(); } // CLS (Cumulative Layout Shift) try { let clsValue = 0; const clsObserver = new PerformanceObserver(list => { list.getEntries().forEach((entry) => { if (!entry.hadRecentInput) { clsValue += entry.value; } }); metrics.cls = clsValue; }); clsObserver.observe({ entryTypes: ['layout-shift'] }); // Stop observing after 10 seconds setTimeout(() => { clsObserver.disconnect(); checkComplete(); }, 10000); } catch { checkComplete(); } } else { // Fallback if PerformanceObserver is not supported setTimeout(() => resolve(metrics), 100); } }); } // Export boost object to match usage examples in upgrade spec const boost = { contentVisibility, fetchPriority, speculate, yieldToBrowser, optimizeImages, preloadCritical, measureCWV }; // Export all functions as named exports and default object var index = { contentVisibility, fetchPriority, speculate, yieldToBrowser, optimizeImages, preloadCritical, measureCWV, boost }; export { boost, contentVisibility, index as default, fetchPriority, measureCWV, optimizeImages, preloadCritical, speculate, yieldToBrowser }; //# sourceMappingURL=perf.esm.js.map