- Standardize script loading on faq, privacy, returns, shipping-info pages - Archive 14 unused JS files (cart-functions, shopping, cart.js, enhanced versions, etc.) - Archive 2 unused CSS files (responsive-enhanced, responsive-fixes) - All pages now use consistent script loading order - Eliminated shopping.js dependency (not needed after standardization)
249 lines
6.8 KiB
JavaScript
249 lines
6.8 KiB
JavaScript
/**
|
|
* 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;
|
|
})();
|