/** * Resource Preloading and Optimization Manager * Manages critical resource loading and performance optimization */ (function () { "use strict"; const ResourceOptimizer = { // Preload critical resources preloadCritical() { const criticalResources = [ { href: "/assets/css/main.css", as: "style" }, { href: "/assets/css/navbar.css", as: "style" }, { href: "/assets/js/main.js", as: "script" }, ]; criticalResources.forEach((resource) => { const link = document.createElement("link"); link.rel = "preload"; link.href = resource.href; link.as = resource.as; if (resource.as === "style") { link.onload = function () { this.rel = "stylesheet"; }; } document.head.appendChild(link); }); }, // Prefetch resources for likely navigation prefetchRoutes() { const routes = [ "/shop.html", "/product.html", "/about.html", "/contact.html", ]; // Prefetch on idle if ("requestIdleCallback" in window) { requestIdleCallback(() => { routes.forEach((route) => { const link = document.createElement("link"); link.rel = "prefetch"; link.href = route; document.head.appendChild(link); }); }); } }, // Defer non-critical scripts deferNonCritical() { const scripts = document.querySelectorAll("script[data-defer]"); const loadScript = (script) => { const newScript = document.createElement("script"); newScript.src = script.dataset.defer; newScript.async = true; document.body.appendChild(newScript); }; if ("requestIdleCallback" in window) { scripts.forEach((script) => { requestIdleCallback(() => loadScript(script)); }); } else { setTimeout(() => { scripts.forEach(loadScript); }, 2000); } }, // Optimize font loading optimizeFonts() { // Use font-display: swap for all fonts if (document.fonts && document.fonts.ready) { document.fonts.ready.then(() => { document.body.classList.add("fonts-loaded"); }); } }, // Reduce main thread work with requestIdleCallback scheduleIdleWork(callback) { if ("requestIdleCallback" in window) { requestIdleCallback(callback, { timeout: 2000 }); } else { setTimeout(callback, 1); } }, // Batch DOM reads and writes batchDOMOperations(operations) { requestAnimationFrame(() => { operations.forEach((op) => op()); }); }, // Monitor performance monitorPerformance() { if ("PerformanceObserver" in window) { // Monitor Long Tasks try { const longTaskObserver = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.duration > 50) { console.warn("Long task detected:", { duration: entry.duration, startTime: entry.startTime, }); } } }); longTaskObserver.observe({ entryTypes: ["longtask"] }); } catch (e) { // Long task API not supported } // Monitor Largest Contentful Paint try { const lcpObserver = new PerformanceObserver((list) => { const entries = list.getEntries(); const lastEntry = entries[entries.length - 1]; console.log("LCP:", lastEntry.renderTime || lastEntry.loadTime); }); lcpObserver.observe({ entryTypes: ["largest-contentful-paint"] }); } catch (e) { // LCP API not supported } } }, // Get performance metrics getMetrics() { if (!window.performance || !window.performance.timing) { return null; } const timing = window.performance.timing; const navigation = window.performance.navigation; return { // Page load metrics domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart, loadComplete: timing.loadEventEnd - timing.navigationStart, // Network metrics dns: timing.domainLookupEnd - timing.domainLookupStart, tcp: timing.connectEnd - timing.connectStart, request: timing.responseStart - timing.requestStart, response: timing.responseEnd - timing.responseStart, // Rendering metrics domProcessing: timing.domComplete - timing.domLoading, domInteractive: timing.domInteractive - timing.navigationStart, // Navigation type navigationType: navigation.type, redirectCount: navigation.redirectCount, }; }, // Log metrics to console (development only) logMetrics() { window.addEventListener("load", () => { setTimeout(() => { const metrics = this.getMetrics(); if (metrics) { console.table(metrics); } }, 0); }); }, // Optimize images optimizeImages() { const images = document.querySelectorAll("img:not([loading])"); images.forEach((img) => { // Add native lazy loading if ("loading" in HTMLImageElement.prototype) { img.loading = "lazy"; } // Add decoding hint img.decoding = "async"; }); }, // Preconnect to external domains preconnectDomains() { const domains = [ "https://fonts.googleapis.com", "https://fonts.gstatic.com", "https://cdn.jsdelivr.net", ]; domains.forEach((domain) => { const link = document.createElement("link"); link.rel = "preconnect"; link.href = domain; link.crossOrigin = "anonymous"; document.head.appendChild(link); }); }, // Initialize all optimizations init() { // Preconnect to external domains early this.preconnectDomains(); // Optimize fonts this.optimizeFonts(); // Optimize existing images this.optimizeImages(); // Monitor performance in development if ( window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" ) { this.monitorPerformance(); this.logMetrics(); } // Defer non-critical resources if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { this.deferNonCritical(); this.prefetchRoutes(); }); } else { this.deferNonCritical(); this.prefetchRoutes(); } }, }; // Auto-initialize ResourceOptimizer.init(); // Export globally window.ResourceOptimizer = ResourceOptimizer; })();