Phase 1: Remove obsolete files and standardize all pages
- 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)
This commit is contained in:
248
website/public/assets/js/archive/resource-optimizer.js
Normal file
248
website/public/assets/js/archive/resource-optimizer.js
Normal file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* 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;
|
||||
})();
|
||||
Reference in New Issue
Block a user