> A robust retry plugin for Module Federation that provides automatic retry mechanisms for failed module requests with domain rotation, cache-busting, and comprehensive error handling.
npm install @module-federation/retry-plugin> A robust retry plugin for Module Federation that provides automatic retry mechanisms for failed module requests with domain rotation, cache-busting, and comprehensive error handling.
- 🔄 Automatic Retry: Automatically retries failed fetch and script requests
- 🌐 Domain Rotation: Rotate through multiple domains for better reliability
- ⚡ Cache Busting: Add query parameters to bypass cache issues
- 📊 Lifecycle Callbacks: Comprehensive callbacks for retry events
- 🎯 Flexible Configuration: Highly configurable retry strategies
- 🔧 TypeScript Support: Full TypeScript support with type definitions
``bash`
npm install @module-federation/retry-pluginor
yarn add @module-federation/retry-pluginor
pnpm add @module-federation/retry-plugin
`ts
import { createInstance } from '@module-federation/enhanced/runtime';
import { RetryPlugin } from '@module-federation/retry-plugin';
const mf = createInstance({
name: 'host',
remotes: [
{
name: 'remote1',
entry: 'http://localhost:2001/mf-manifest.json',
}
],
plugins: [
RetryPlugin({
retryTimes: 3,
retryDelay: 1000,
domains: ['https://cdn1.example.com', 'https://cdn2.example.com'],
manifestDomains: ['https://domain1.example.com', 'https://domain2.example.com'],
addQuery: ({ times, originalQuery }) => ${originalQuery}&retry=${times},`
onRetry: ({ times, url }) => console.log('Retrying...', times, url),
onSuccess: ({ url }) => console.log('Success!', url),
onError: ({ url }) => console.log('Failed!', url),
}),
]
});
`ts
// webpack.config.js
import { ModuleFederationPlugin } from '@module-federation/webpack';
import { RetryPlugin } from '@module-federation/retry-plugin';
export default {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
remote1: 'remote1@http://localhost:2001/mf-manifest.json',
},
runtimePlugins: [
path.join(__dirname, './src/runtime-plugin/retry.ts'),
],
}),
],
};
`
`ts
// src/runtime-plugin/retry.ts
import { RetryPlugin } from '@module-federation/retry-plugin';
export default () => RetryPlugin({
retryTimes: 3,
retryDelay: 1000,
domains: ['https://cdn1.example.com', 'https://cdn2.example.com'],
manifestDomains: ['https://domain1.example.com', 'https://domain2.example.com'],
addQuery: ({ times, originalQuery }) => ${originalQuery}&retry=${times},`
onRetry: ({ times, url }) => console.log('Retrying...', times, url),
onSuccess: ({ url }) => console.log('Success!', url),
onError: ({ url }) => console.log('Failed!', url),
});
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| retryTimes | number | 3 | Number of retry attempts |retryDelay
| | number | 1000 | Delay between retries in milliseconds |successTimes
| | number | 0 | Number of successful requests required |domains
| | string[] | [] | Alternative domains for script resources |manifestDomains
| | string[] | [] | Alternative domains for manifest files |addQuery
| | boolean \| function | false | Add query parameters for cache busting |fetchOptions
| | RequestInit | {} | Additional fetch options |onRetry
| | function | undefined | Callback when retry occurs |onSuccess
| | function | undefined | Callback when request succeeds |onError
| | function | undefined | Callback when all retries fail |
`ts${originalQuery}${separator}retry=${times}&t=${Date.now()}
addQuery: ({ times, originalQuery }) => {
// Add retry count and timestamp for cache busting
const separator = originalQuery ? '&' : '?';
return ;`
}
`tsRetry attempt ${times} for ${url}
onRetry: ({ times, domains, url, tagName }) => {
console.log();Available domains: ${domains?.join(', ')}
console.log();
},
onSuccess: ({ domains, url, tagName }) => {
console.log(Successfully loaded ${url});Used domain: ${domains?.[0]}
console.log();
},
onError: ({ domains, url, tagName }) => {
console.error(Failed to load ${url} after all retries);Tried domains: ${domains?.join(', ')}
console.error();`
}
`tsRetry ${times}/5 for ${url}
RetryPlugin({
retryTimes: 5,
retryDelay: (attempt) => Math.pow(2, attempt) * 1000, // Exponential backoff
domains: [
'https://cdn1.example.com',
'https://cdn2.example.com',
'https://cdn3.example.com',
],
manifestDomains: [
'https://api1.example.com',
'https://api2.example.com',
],
addQuery: ({ times, originalQuery }) => {
const params = new URLSearchParams(originalQuery);
params.set('retry', times.toString());
params.set('cache_bust', Date.now().toString());
return params.toString();
},
onRetry: ({ times, url, domains }) => {
console.log();Trying domain: ${domains?.[times % domains.length]}
console.log();✅ Successfully loaded ${url}
},
onSuccess: ({ url, domains }) => {
console.log();✅ Used domain: ${domains?.[0]}
console.log();❌ Failed to load ${url} after all retries
},
onError: ({ url, domains }) => {
console.error();❌ Tried all domains: ${domains?.join(', ')}
console.error();`
},
})
`ts
RetryPlugin({
retryTimes: 3,
retryDelay: 1000,
domains: ['https://cdn1.example.com', 'https://cdn2.example.com'],
onError: ({ url, domains }) => {
// Log error for monitoring
console.error('Module loading failed:', { url, domains });
// Send error to monitoring service
if (window.gtag) {
window.gtag('event', 'module_load_error', {
event_category: 'module_federation',
event_label: url,
value: domains?.length || 0,
});
}
// Show user-friendly error message
const errorElement = document.createElement('div');
errorElement.className = 'module-load-error';
errorElement.innerHTML =
Unable to load module: ${url}
Please refresh the page to try again.
;
document.body.appendChild(errorElement);
},
})
`$3
`ts
RetryPlugin({
retryTimes: 3,
retryDelay: 1000,
domains: [
'https://cdn1.prod.example.com',
'https://cdn2.prod.example.com',
'https://cdn3.prod.example.com',
],
manifestDomains: [
'https://api1.prod.example.com',
'https://api2.prod.example.com',
],
addQuery: ({ times, originalQuery }) => {
const params = new URLSearchParams(originalQuery);
params.set('retry', times.toString());
params.set('v', process.env.BUILD_VERSION || '1.0.0');
return params.toString();
},
fetchOptions: {
cache: 'no-cache',
headers: {
'X-Requested-With': 'ModuleFederation',
},
},
onRetry: ({ times, url }) => {
// Only log in development
if (process.env.NODE_ENV === 'development') {
console.log(Retry ${times} for ${url});
}
},
onSuccess: ({ url }) => {
// Track successful loads
if (window.analytics) {
window.analytics.track('module_loaded', { url });
}
},
onError: ({ url, domains }) => {
// Send error to monitoring service
if (window.errorReporting) {
window.errorReporting.captureException(
new Error(Module loading failed: ${url}),
{ extra: { domains, url } }
);
}
},
})
`How It Works
1. Fetch Retry: Intercepts failed fetch requests for manifest files and retries with domain rotation
2. Script Retry: Intercepts failed script loading and retries with alternative domains
3. Domain Rotation: Cycles through provided domains to find working alternatives
4. Cache Busting: Adds query parameters to prevent cache-related issues
5. Lifecycle Hooks: Provides callbacks for monitoring and debugging
Error Scenarios Handled
- Network timeouts and connection errors
- DNS resolution failures
- Server errors (5xx status codes)
- CDN failures and regional issues
- Cache-related loading problems
- CORS and security policy violations
Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
TypeScript Support
The plugin includes full TypeScript definitions:
`ts
import { RetryPlugin, type CommonRetryOptions } from '@module-federation/retry-plugin';const options: CommonRetryOptions = {
retryTimes: 3,
retryDelay: 1000,
domains: ['https://cdn1.example.com'],
onRetry: ({ times, url }) => {
console.log(
Retry ${times} for ${url});
},
};const plugin = RetryPlugin(options);
`Migration Guide
$3
The plugin configuration has been simplified. The old
fetch and script configuration objects are deprecated:`ts
// ❌ Old way (deprecated)
RetryPlugin({
fetch: {
url: 'http://localhost:2008/not-exist-mf-manifest.json',
fallback: () => 'http://localhost:2001/mf-manifest.json',
},
script: {
url: 'http://localhost:2001/static/js/async/src_App_tsx.js',
customCreateScript: (url, attrs) => { / ... / },
}
})// ✅ New way
RetryPlugin({
retryTimes: 3,
retryDelay: 1000,
domains: ['http://localhost:2001'],
manifestDomains: ['http://localhost:2001'],
addQuery: ({ times, originalQuery }) =>
${originalQuery}&retry=${times},
})
`Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
License
@module-federation/retry-plugin` is MIT licensed.- Module Federation Documentation
- Module Federation Runtime
- Module Federation Enhanced