Resource Loading Optimization
Resource Loading Optimization
CSP can impact resource loading performance. Here's how to optimize:
// Resource Loading Optimizer
class CSPResourceOptimizer {
constructor() {
this.resourcePatterns = new Map();
this.loadingStrategies = this.defineLoadingStrategies();
}
defineLoadingStrategies() {
return {
scripts: {
preload: true,
async: true,
defer: true,
bundling: true,
recommendations: [
'Use resource hints with CSP-compliant sources',
'Bundle first-party scripts to reduce CSP checks',
'Implement progressive loading for non-critical scripts'
]
},
styles: {
critical: true,
preload: true,
bundling: true,
recommendations: [
'Inline critical CSS with nonces',
'Preload external stylesheets',
'Use CSS-in-JS with CSP support'
]
},
images: {
lazy: true,
responsive: true,
optimization: true,
recommendations: [
'Implement lazy loading for below-fold images',
'Use srcset for responsive images',
'Optimize image formats and compression'
]
}
};
}
optimizeResourceLoading() {
return `
// CSP-aware resource loader
class CSPResourceLoader {
constructor(cspNonce) {
this.nonce = cspNonce;
this.loadedResources = new Set();
this.pendingResources = new Map();
}
// Optimized script loading with CSP
async loadScript(src, options = {}) {
// Check if already loaded
if (this.loadedResources.has(src)) {
return Promise.resolve();
}
// Check if loading in progress
if (this.pendingResources.has(src)) {
return this.pendingResources.get(src);
}
const loadPromise = new Promise((resolve, reject) => {
const script = document.createElement('script');
// CSP compliance
if (this.nonce) {
script.nonce = this.nonce;
}
// Performance optimizations
script.async = options.async !== false;
script.defer = options.defer || false;
// Resource hints
if (options.preload) {
this.preloadResource(src, 'script');
}
script.onload = () => {
this.loadedResources.add(src);
this.pendingResources.delete(src);
resolve();
};
script.onerror = () => {
this.pendingResources.delete(src);
reject(new Error(\`Failed to load script: \${src}\`));
};
script.src = src;
document.head.appendChild(script);
});
this.pendingResources.set(src, loadPromise);
return loadPromise;
}
// Preload resources with CSP compliance
preloadResource(href, as) {
const link = document.createElement('link');
link.rel = 'preload';
link.as = as;
link.href = href;
if (as === 'script' || as === 'style') {
link.nonce = this.nonce;
}
document.head.appendChild(link);
}
// Bundle loader for reduced CSP overhead
async loadBundle(resources) {
const results = await Promise.allSettled(
resources.map(resource => {
if (typeof resource === 'string') {
return this.loadScript(resource);
} else {
return this.loadScript(resource.src, resource.options);
}
})
);
const failed = results.filter(r => r.status === 'rejected');
if (failed.length > 0) {
console.warn('Some resources failed to load:', failed);
}
return results;
}
}
`;
}
implementProgressiveEnhancement() {
return {
criticalPath: `
// Load critical resources first
(async function() {
const loader = new CSPResourceLoader(window.__CSP_NONCE__);
// Critical resources
await loader.loadBundle([
{ src: '/js/core.js', options: { preload: true } },
{ src: '/js/critical-path.js', options: { async: false } }
]);
// Non-critical resources
requestIdleCallback(() => {
loader.loadBundle([
'/js/analytics.js',
'/js/social-widgets.js',
'/js/enhancement.js'
]);
});
})();
`,
lazyLoading: `
// Intersection Observer for lazy loading with CSP
class CSPLazyLoader {
constructor(nonce) {
this.nonce = nonce;
this.observer = this.createObserver();
}
createObserver() {
return new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadResource(entry.target);
this.observer.unobserve(entry.target);
}
});
}, {
rootMargin: '50px'
});
}
loadResource(element) {
if (element.dataset.src) {
if (element.tagName === 'SCRIPT') {
const script = document.createElement('script');
script.src = element.dataset.src;
script.nonce = this.nonce;
element.parentNode.replaceChild(script, element);
} else if (element.tagName === 'IMG') {
element.src = element.dataset.src;
element.removeAttribute('data-src');
}
}
}
observe(selector) {
document.querySelectorAll(selector).forEach(el => {
this.observer.observe(el);
});
}
}
`
};
}
}