Modern Polyfill Loading and Distribution

1. Differential Serving and Modern/Legacy Bundles

Approach Modern Bundle Legacy Bundle Detection Method
Module/Nomodule <script type="module"> <script nomodule> Browser feature detection
User Agent ES2015+ syntax ES5 + polyfills Server-side UA parsing
Feature Test Native features Polyfilled features Client-side detection
Bundle Size Savings 30-50% smaller Full compatibility Varies by project
Browser Support Modern (ES2015+) IE11, old Safari Graceful degradation

Example: Module/nomodule pattern

<!-- Modern browsers load ES modules -->
<script type="module" src="app.modern.js"></script>

<!-- Legacy browsers load ES5 + polyfills -->
<script nomodule src="app.legacy.js"></script>

<!-- 
Modern bundle (app.modern.js):
- ES2015+ syntax (arrow functions, classes, etc.)
- No polyfills for Promise, fetch, etc.
- Native modules, async/await
- ~30-40% smaller

Legacy bundle (app.legacy.js):
- Transpiled to ES5
- Includes core-js polyfills
- Promise, fetch, Symbol polyfills
- Full compatibility
-->

Example: Dynamic differential serving

// Client-side differential serving
(function() {
    // Feature detection for modern bundle
    var isModern = (
        'fetch' in window &&
        'Promise' in window &&
        'assign' in Object &&
        'keys' in Object &&
        'symbol' in window.Symbol
    );
    
    function loadBundle(modern) {
        var script = document.createElement('script');
        
        if (modern) {
            script.type = 'module';
            script.src = '/dist/app.modern.js';
        } else {
            script.src = '/dist/app.legacy.js';
            script.defer = true;
        }
        
        document.head.appendChild(script);
    }
    
    // Load appropriate bundle
    loadBundle(isModern);
})();

// Webpack configuration for differential builds
// webpack.config.js
module.exports = [
    {
        // Modern build
        name: 'modern',
        output: {
            filename: 'app.modern.js',
            module: true
        },
        target: ['web', 'es2015'],
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                ['@babel/preset-env', {
                                    targets: { esmodules: true },
                                    bugfixes: true,
                                    shippedProposals: true
                                }]
                            ]
                        }
                    }
                }
            ]
        }
    },
    {
        // Legacy build
        name: 'legacy',
        output: {
            filename: 'app.legacy.js'
        },
        target: ['web', 'es5'],
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                ['@babel/preset-env', {
                                    targets: '> 0.5%, last 2 versions, Firefox ESR, not dead, IE 11',
                                    useBuiltIns: 'usage',
                                    corejs: 3
                                }]
                            ]
                        }
                    }
                }
            ]
        }
    }
];
Note: Differential serving can reduce bundle sizes by 30-50% for modern browsers while maintaining backward compatibility. Use module/nomodule for automatic detection.

2. Dynamic Import and Code Splitting Strategies

Strategy Use Case Loading Time Implementation
Route-based Load code per page/route On navigation import('./page.js')
Component-based Lazy load components On visibility/interaction React.lazy, Vue async
Vendor chunks Separate node_modules Initial load splitChunks config
Polyfill chunks Load only if needed Conditional Feature detection + import()
Prefetch/Preload Anticipate future needs Idle time <link rel="prefetch">

Example: Conditional polyfill loading

// Load polyfills only when needed
async function loadPolyfills() {
    var polyfills = [];
    
    // Check what's needed
    if (!('Promise' in window)) {
        polyfills.push(import('core-js/features/promise'));
    }
    
    if (!('fetch' in window)) {
        polyfills.push(import('whatwg-fetch'));
    }
    
    if (!('IntersectionObserver' in window)) {
        polyfills.push(import('intersection-observer'));
    }
    
    if (!window.customElements) {
        polyfills.push(import('@webcomponents/webcomponentsjs/webcomponents-bundle'));
    }
    
    // Wait for all polyfills to load
    if (polyfills.length > 0) {
        await Promise.all(polyfills);
        console.log('Polyfills loaded:', polyfills.length);
    }
}

// Initialize app after polyfills
loadPolyfills()
    .then(() => {
        return import('./app.js');
    })
    .then((app) => {
        app.init();
    })
    .catch((error) => {
        console.error('Failed to load:', error);
    });

// Webpack magic comments for chunk naming
async function loadFeature() {
    const module = await import(
        /* webpackChunkName: "heavy-feature" */
        /* webpackPrefetch: true */
        './heavy-feature.js'
    );
    
    return module;
}

Example: Progressive polyfill loader

// Progressive polyfill loading system
var PolyfillLoader = {
    required: [],
    loaded: new Set(),
    
    register: function(name, test, loader) {
        this.required.push({
            name: name,
            test: test,
            loader: loader
        });
    },
    
    loadAll: function() {
        var self = this;
        var promises = [];
        
        this.required.forEach(function(polyfill) {
            if (!polyfill.test()) {
                console.log('Loading polyfill:', polyfill.name);
                
                var promise = polyfill.loader()
                    .then(function() {
                        self.loaded.add(polyfill.name);
                        console.log('Loaded:', polyfill.name);
                    })
                    .catch(function(error) {
                        console.error('Failed to load:', polyfill.name, error);
                    });
                
                promises.push(promise);
            } else {
                console.log('Native support:', polyfill.name);
            }
        });
        
        return Promise.all(promises);
    }
};

// Register polyfills
PolyfillLoader.register(
    'Promise',
    function() { return 'Promise' in window; },
    function() { return import('es6-promise/auto'); }
);

PolyfillLoader.register(
    'fetch',
    function() { return 'fetch' in window; },
    function() { return import('whatwg-fetch'); }
);

PolyfillLoader.register(
    'IntersectionObserver',
    function() { return 'IntersectionObserver' in window; },
    function() { return import('intersection-observer'); }
);

PolyfillLoader.register(
    'ResizeObserver',
    function() { return 'ResizeObserver' in window; },
    function() { return import('resize-observer-polyfill'); }
);

// Load and initialize
PolyfillLoader.loadAll().then(function() {
    console.log('All required polyfills loaded');
    console.log('Loaded polyfills:', Array.from(PolyfillLoader.loaded));
    
    // Initialize application
    initApp();
});
Note: Dynamic imports enable on-demand polyfill loading, reducing initial bundle size. Use feature detection to load only what's needed.

3. Polyfill.io Service Integration and Configuration

Feature Configuration Benefits Considerations
Auto Detection UA-based polyfill selection Optimal bundle per browser CDN dependency
Custom Features ?features=Promise,fetch Request specific polyfills Manual configuration
Flags ?flags=gated,always Control loading behavior Advanced usage
Self-hosted Run own polyfill service Full control, no third-party Maintenance overhead
Security Warning Service compromised 2024 - USE WITH CAUTION

Example: Self-hosted polyfill service alternative

// Self-hosted polyfill service (safer alternative)
// polyfill-service.js
var PolyfillService = {
    polyfills: {
        'Promise': {
            detect: function() { return 'Promise' in window; },
            url: '/polyfills/promise.min.js'
        },
        'fetch': {
            detect: function() { return 'fetch' in window; },
            url: '/polyfills/fetch.min.js'
        },
        'IntersectionObserver': {
            detect: function() { return 'IntersectionObserver' in window; },
            url: '/polyfills/intersection-observer.min.js'
        },
        'Array.prototype.includes': {
            detect: function() { return Array.prototype.includes; },
            url: '/polyfills/array-includes.min.js'
        },
        'Object.assign': {
            detect: function() { return Object.assign; },
            url: '/polyfills/object-assign.min.js'
        }
    },
    
    load: function(features) {
        var self = this;
        var scripts = [];
        
        features.forEach(function(feature) {
            var polyfill = self.polyfills[feature];
            
            if (!polyfill) {
                console.warn('Unknown polyfill:', feature);
                return;
            }
            
            if (!polyfill.detect()) {
                scripts.push(self._loadScript(polyfill.url));
            }
        });
        
        return Promise.all(scripts);
    },
    
    _loadScript: function(url) {
        return new Promise(function(resolve, reject) {
            var script = document.createElement('script');
            script.src = url;
            script.async = true;
            
            script.onload = function() {
                console.log('Loaded:', url);
                resolve();
            };
            
            script.onerror = function() {
                console.error('Failed to load:', url);
                reject(new Error('Script load failed: ' + url));
            };
            
            document.head.appendChild(script);
        });
    },
    
    loadAll: function() {
        var features = Object.keys(this.polyfills);
        return this.load(features);
    },
    
    // Parse URL parameters to load specific features
    loadFromURL: function() {
        var params = new URLSearchParams(window.location.search);
        var features = params.get('features');
        
        if (features) {
            var featureList = features.split(',');
            return this.load(featureList);
        }
        
        return this.loadAll();
    }
};

// Usage - load specific polyfills
PolyfillService.load(['Promise', 'fetch', 'IntersectionObserver'])
    .then(function() {
        console.log('Polyfills ready');
        initApp();
    })
    .catch(function(error) {
        console.error('Polyfill loading failed:', error);
    });

// Or load based on URL: /app.html?features=Promise,fetch
// PolyfillService.loadFromURL();
Warning: The public polyfill.io CDN was compromised in 2024. Self-host polyfills or use trusted alternatives like cdnjs or jsDelivr with SRI hashes.

4. CDN-based Polyfill Loading Strategies

CDN Provider Reliability Features Security
jsDelivr High (multi-CDN) NPM packages, GitHub releases SRI support
cdnjs High (Cloudflare) Curated library collection SRI support
unpkg Medium Direct NPM access SRI recommended
Self-hosted Depends on infrastructure Full control Your responsibility
Hybrid Best (fallback chain) CDN + local fallback Multiple layers

Example: CDN loading with fallback

// CDN loader with fallback chain
var CDNLoader = {
    sources: [
        {
            name: 'jsDelivr',
            url: 'https://cdn.jsdelivr.net/npm/core-js-bundle@3.27.2/minified.js',
            integrity: 'sha384-...'
        },
        {
            name: 'cdnjs',
            url: 'https://cdnjs.cloudflare.com/ajax/libs/core-js/3.27.2/minified.js',
            integrity: 'sha384-...'
        },
        {
            name: 'unpkg',
            url: 'https://unpkg.com/core-js-bundle@3.27.2/minified.js',
            integrity: 'sha384-...'
        },
        {
            name: 'local',
            url: '/js/polyfills/core-js.min.js',
            integrity: null
        }
    ],
    
    currentIndex: 0,
    
    load: function(callback) {
        this._tryLoad(callback);
    },
    
    _tryLoad: function(callback) {
        if (this.currentIndex >= this.sources.length) {
            callback(new Error('All sources failed'));
            return;
        }
        
        var source = this.sources[this.currentIndex];
        console.log('Trying:', source.name);
        
        var script = document.createElement('script');
        script.src = source.url;
        script.async = true;
        
        if (source.integrity) {
            script.integrity = source.integrity;
            script.crossOrigin = 'anonymous';
        }
        
        var self = this;
        
        script.onload = function() {
            console.log('Loaded from:', source.name);
            callback(null, source.name);
        };
        
        script.onerror = function() {
            console.warn('Failed from:', source.name);
            self.currentIndex++;
            self._tryLoad(callback);
        };
        
        document.head.appendChild(script);
    }
};

// Usage
CDNLoader.load(function(err, source) {
    if (err) {
        console.error('All CDN sources failed:', err);
        return;
    }
    
    console.log('Successfully loaded from:', source);
    initApp();
});

Example: Optimized CDN selection

// Smart CDN selector based on geography and performance
var SmartCDN = {
    cdns: [
        {
            name: 'jsDelivr',
            baseUrl: 'https://cdn.jsdelivr.net/npm/',
            regions: ['global']
        },
        {
            name: 'cdnjs',
            baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/',
            regions: ['global']
        }
    ],
    
    measureLatency: function(url) {
        return new Promise(function(resolve) {
            var start = performance.now();
            var img = new Image();
            
            img.onload = img.onerror = function() {
                var latency = performance.now() - start;
                resolve(latency);
            };
            
            // Append timestamp to prevent caching
            img.src = url + '?t=' + Date.now();
        });
    },
    
    selectFastest: function() {
        var self = this;
        
        var tests = this.cdns.map(function(cdn) {
            var testUrl = cdn.baseUrl.replace(/\/[^\/]*$/, '/favicon.ico');
            
            return self.measureLatency(testUrl).then(function(latency) {
                return { cdn: cdn, latency: latency };
            });
        });
        
        return Promise.all(tests).then(function(results) {
            results.sort(function(a, b) {
                return a.latency - b.latency;
            });
            
            console.log('CDN latencies:', results);
            return results[0].cdn;
        });
    },
    
    loadFrom: function(cdn, packagePath) {
        return new Promise(function(resolve, reject) {
            var script = document.createElement('script');
            script.src = cdn.baseUrl + packagePath;
            script.async = true;
            script.crossOrigin = 'anonymous';
            
            script.onload = function() {
                resolve(cdn.name);
            };
            
            script.onerror = function() {
                reject(new Error('Failed from ' + cdn.name));
            };
            
            document.head.appendChild(script);
        });
    }
};

// Usage
SmartCDN.selectFastest()
    .then(function(fastestCDN) {
        console.log('Using fastest CDN:', fastestCDN.name);
        return SmartCDN.loadFrom(fastestCDN, 'core-js-bundle@3.27.2/minified.js');
    })
    .then(function(source) {
        console.log('Loaded from:', source);
    })
    .catch(function(error) {
        console.error('CDN loading failed:', error);
    });
Note: Use multiple CDN fallbacks for reliability. Always include local fallback and use SRI hashes for security.

5. Service Worker and Offline Polyfill Caching

Strategy Description Use Case Cache Priority
Cache First Serve from cache, fallback to network Static polyfills High
Network First Try network, fallback to cache Frequently updated polyfills Medium
Stale While Revalidate Serve cache, update in background Best of both worlds Balanced
Network Only Always fetch from network Development None
Cache Only Only serve cached content Offline-first apps Required

Example: Service Worker for polyfill caching

// service-worker.js
var CACHE_NAME = 'polyfills-v1';
var POLYFILL_URLS = [
    '/polyfills/core-js.min.js',
    '/polyfills/fetch.min.js',
    '/polyfills/intersection-observer.min.js',
    '/polyfills/resize-observer.min.js'
];

// Install - cache polyfills
self.addEventListener('install', function(event) {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(function(cache) {
                console.log('Caching polyfills');
                return cache.addAll(POLYFILL_URLS);
            })
            .then(function() {
                return self.skipWaiting();
            })
    );
});

// Activate - cleanup old caches
self.addEventListener('activate', function(event) {
    event.waitUntil(
        caches.keys()
            .then(function(cacheNames) {
                return Promise.all(
                    cacheNames.map(function(cacheName) {
                        if (cacheName !== CACHE_NAME) {
                            console.log('Deleting old cache:', cacheName);
                            return caches.delete(cacheName);
                        }
                    })
                );
            })
            .then(function() {
                return self.clients.claim();
            })
    );
});

// Fetch - serve from cache with network fallback
self.addEventListener('fetch', function(event) {
    var url = new URL(event.request.url);
    
    // Only handle polyfill requests
    if (url.pathname.indexOf('/polyfills/') !== 0) {
        return;
    }
    
    event.respondWith(
        caches.match(event.request)
            .then(function(response) {
                if (response) {
                    console.log('Serving from cache:', url.pathname);
                    return response;
                }
                
                console.log('Fetching from network:', url.pathname);
                return fetch(event.request)
                    .then(function(response) {
                        // Cache the new response
                        if (response.status === 200) {
                            var responseClone = response.clone();
                            caches.open(CACHE_NAME)
                                .then(function(cache) {
                                    cache.put(event.request, responseClone);
                                });
                        }
                        
                        return response;
                    });
            })
            .catch(function() {
                console.error('Failed to load:', url.pathname);
            })
    );
});

// Register service worker (in main app)
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
        .then(function(registration) {
            console.log('Service Worker registered:', registration);
        })
        .catch(function(error) {
            console.error('Service Worker registration failed:', error);
        });
}

Example: Stale-while-revalidate strategy

// Advanced caching with stale-while-revalidate
self.addEventListener('fetch', function(event) {
    var url = new URL(event.request.url);
    
    if (url.pathname.indexOf('/polyfills/') !== 0) {
        return;
    }
    
    event.respondWith(
        caches.open(CACHE_NAME).then(function(cache) {
            return cache.match(event.request).then(function(cachedResponse) {
                // Fetch from network in background
                var fetchPromise = fetch(event.request).then(function(networkResponse) {
                    // Update cache with fresh response
                    if (networkResponse.status === 200) {
                        cache.put(event.request, networkResponse.clone());
                    }
                    return networkResponse;
                });
                
                // Return cached response immediately if available
                // Otherwise wait for network
                return cachedResponse || fetchPromise;
            });
        })
    );
});
Note: Service Workers enable offline-first polyfill delivery. Use cache-first strategy for stable polyfills, network-first for frequently updated ones.

6. HTTP/2 Push and Preload Optimization

Technique Syntax Timing Use Case
HTTP/2 Server Push Server-side configuration Before HTML parsed Critical polyfills
Preload <link rel="preload"> High priority, immediate Required resources
Prefetch <link rel="prefetch"> Low priority, future use Next page resources
Preconnect <link rel="preconnect"> DNS + TLS handshake CDN connections
DNS Prefetch <link rel="dns-prefetch"> DNS resolution only External domains

Example: Resource hints for polyfills

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Optimized Polyfill Loading</title>
    
    <!-- Preconnect to CDNs -->
    <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
    <link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
    
    <!-- DNS prefetch for backup CDN -->
    <link rel="dns-prefetch" href="https://unpkg.com">
    
    <!-- Preload critical polyfills -->
    <link rel="preload" 
          href="/polyfills/core-js.min.js" 
          as="script" 
          crossorigin>
    
    <link rel="preload" 
          href="/polyfills/fetch.min.js" 
          as="script" 
          crossorigin>
    
    <!-- Prefetch polyfills for next page -->
    <link rel="prefetch" 
          href="/polyfills/intersection-observer.min.js" 
          as="script">
    
    <!-- Load critical polyfills with high priority -->
    <script src="/polyfills/core-js.min.js" defer></script>
    <script src="/polyfills/fetch.min.js" defer></script>
</head>
<body>
    <!-- App content -->
</body>
</html>

Example: Dynamic preload injection

// Dynamic resource hint injection
var ResourceHints = {
    preload: function(url, as, crossorigin) {
        var link = document.createElement('link');
        link.rel = 'preload';
        link.href = url;
        link.as = as || 'script';
        
        if (crossorigin) {
            link.crossOrigin = crossorigin;
        }
        
        document.head.appendChild(link);
    },
    
    prefetch: function(url, as) {
        var link = document.createElement('link');
        link.rel = 'prefetch';
        link.href = url;
        
        if (as) {
            link.as = as;
        }
        
        document.head.appendChild(link);
    },
    
    preconnect: function(url, crossorigin) {
        var link = document.createElement('link');
        link.rel = 'preconnect';
        link.href = url;
        
        if (crossorigin) {
            link.crossOrigin = crossorigin;
        }
        
        document.head.appendChild(link);
    },
    
    // Preload polyfills based on feature detection
    preloadIfNeeded: function() {
        if (!('IntersectionObserver' in window)) {
            this.preload('/polyfills/intersection-observer.min.js', 'script');
        }
        
        if (!('ResizeObserver' in window)) {
            this.preload('/polyfills/resize-observer.min.js', 'script');
        }
        
        if (!window.customElements) {
            this.preload('/polyfills/custom-elements.min.js', 'script');
        }
    }
};

// Setup preconnections early
ResourceHints.preconnect('https://cdn.jsdelivr.net', 'anonymous');
ResourceHints.preconnect('https://cdnjs.cloudflare.com', 'anonymous');

// Preload needed polyfills
ResourceHints.preloadIfNeeded();

// Prefetch polyfills for next page
document.addEventListener('DOMContentLoaded', function() {
    // Prefetch during idle time
    if ('requestIdleCallback' in window) {
        requestIdleCallback(function() {
            ResourceHints.prefetch('/next-page/polyfills.js', 'script');
        });
    }
});

Key Takeaways - Modern Loading & Distribution

  • Differential Serving: 30-50% smaller bundles for modern browsers with module/nomodule
  • Dynamic Import: Load polyfills on-demand based on feature detection
  • Self-hosted: Safer than public CDNs, avoid compromised polyfill.io
  • CDN Fallbacks: Multiple sources with SRI hashes, local backup required
  • Service Workers: Cache-first strategy for offline reliability
  • Resource Hints: Preload critical, prefetch future, preconnect to CDNs