# 重试插件 重试插件为 Module Federation 提供强大的资源加载失败重试机制,当远程模块或资源加载失败时,自动进行重试以确保应用的稳定性。 ## 功能特性 - **自动重试**: 资源加载失败时自动重试,提高应用稳定性 - **域名轮换**: 支持多个备用域名,自动切换到可用的域名 - **缓存破坏**: 通过添加查询参数避免浏览器缓存影响重试结果 - **灵活配置**: 支持自定义重试次数、延迟时间和回调函数 ## 安装 ```bash npm install @module-federation/retry-plugin ``` ## 迁移指南 ### 从 v0.18.x 到 v0.19.x 插件配置已经简化。旧的 `fetch` 和 `script` 配置对象已被弃用: ```ts // ❌ 旧方式(已弃用) 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) => { /* ... */ }, } }) // ✅ 新方式 RetryPlugin({ retryTimes: 3, retryDelay: 1000, domains: ['http://localhost:2001'], manifestDomains: ['http://localhost:2001'], addQuery: ({ times, originalQuery }) => `${originalQuery}&retry=${times}`, }) ``` ## 使用方法 ### 方式一:构建插件中使用 ```ts title="rspack.config.ts" import { pluginModuleFederation } from '@module-federation/rsbuild-plugin'; import { defineConfig } from '@rsbuild/core'; export default defineConfig({ plugins: [ pluginReact(), pluginModuleFederation({ runtimePlugins: [ path.join(__dirname, './src/runtime-plugin/retry.ts'), ], }), ], }); ``` ```ts // ./src/runtime-plugin/retry.ts import { RetryPlugin } from '@module-federation/retry-plugin'; const retryPlugin = () => RetryPlugin({ retryTimes: 3, retryDelay: 1000, manifestDomains: ['https://domain1.example.com', 'https://domain2.example.com'], domains: ['https://cdn1.example.com', 'https://cdn2.example.com'], addQuery: ({ times, originalQuery }) => `${originalQuery}&retry=${times}`, onRetry: ({ times, url }) => console.log('retry', times, url), onSuccess: ({ url }) => console.log('success', url), onError: ({ url }) => console.log('error', url), }) export default retryPlugin; ``` ### 方式二:运行时注册 ```ts import { createInstance, loadRemote } from '@module-federation/enhanced/runtime'; import { RetryPlugin } from '@module-federation/retry-plugin'; const mf = createInstance({ name: 'federation_consumer', remotes: [], plugins: [ RetryPlugin({ retryTimes: 3, retryDelay: 1000, manifestDomains: ['https://domain1.example.com', 'https://domain2.example.com'], domains: ['https://cdn1.example.com', 'https://cdn2.example.com'], addQuery: ({ times, originalQuery }) => `${originalQuery}&retry=${times}`, onRetry: ({ times, url }) => console.log('retry', times, url), onSuccess: ({ url }) => console.log('success', url), onError: ({ url }) => console.log('error', url), }), ], }); ``` ## 配置参数 ### 基础配置 **retryTimes** - 类型:`number` - 可选 - 重试的次数,默认为 3 **retryDelay** - 类型:`number` - 可选 - 重试间隔时间(毫秒),默认为 1000 ### 高级配置 **domains** - 类型:`string[]` - 可选 - 备用域名列表,用于域名轮换重试,默认为空数组 **addQuery** - 类型:`boolean | ((context: { times: number; originalQuery: string }) => string)` - 可选 - 是否在重试时添加查询参数,默认为 false - 当为函数时,接收重试次数和原始查询字符串,返回新的查询字符串 **fetchOptions** - 类型:`RequestInit` - 可选 - 自定义 fetch 请求选项,默认为空对象 **manifestDomains** - 类型:`string[]` - 可选 - 用于 `mf-manifest.json` 资源的域名轮换列表(优先级高于 `domains`)。当配置了 `manifestDomains` 时,插件在获取 `mf-manifest.json` 等清单资源的重试中,会优先按 `manifestDomains` 顺序进行域名切换;其他资源仍使用 `domains`。 ### 回调函数 **onRetry** - 类型:`({ times, domains, url, tagName }: { times?: number; domains?: string[]; url?: string; tagName?: string }) => void` - 可选 - 重试时触发的回调函数 - 参数:`times` 重试次数,`domains` 域名列表,`url` 请求URL,`tagName` 资源类型 **onSuccess** - 类型:`({ domains, url, tagName }: { domains?: string[]; url?: string; tagName?: string; }) => void` - 可选 - 重试成功时触发的回调函数 - 参数:`domains` 域名列表,`url` 请求URL,`tagName` 资源类型 **onError** - 类型:`({ domains, url, tagName }: { domains?: string[]; url?: string; tagName?: string; }) => void` - 可选 - 重试最终失败时触发的回调函数 - 参数:`domains` 域名列表,`url` 请求URL,`tagName` 资源类型 ## 详细说明 ### 重试机制 插件会在资源加载失败时自动进行重试,重试次数由 `retryTimes` 参数控制。例如: - `retryTimes: 3` 表示总共尝试 4 次(1次初始尝试 + 3次重试) - 每次重试前会等待 `retryDelay` 毫秒 ### 域名轮换 当配置了 `domains` 参数时,插件会在重试时自动切换到下一个域名: ```javascript const retryPlugin = RetryPlugin({ domains: [ 'https://cdn1.example.com', 'https://cdn2.example.com', 'https://cdn3.example.com' ], }); ``` 重试顺序: 1. 首次尝试:原始 URL 2. 第1次重试:切换到 `cdn2.example.com` 3. 第2次重试:切换到 `cdn3.example.com` 4. 第3次重试:切换到 `cdn1.example.com` ### 缓存破坏 通过 `addQuery` 参数可以在重试时添加查询参数,避免浏览器缓存影响: ```javascript const retryPlugin = RetryPlugin({ addQuery: true, // 添加 ?retryCount=1, ?retryCount=2 等 }); ``` 也可以使用自定义函数: ```javascript const retryPlugin = RetryPlugin({ addQuery: ({ times, originalQuery }) => { return `${originalQuery}&retry=${times}&timestamp=${Date.now()}`; }, }); ``` ### 回调函数 插件提供了三个回调函数,让你可以监控重试过程: ```javascript const retryPlugin = RetryPlugin({ onRetry: ({ times, domains, url, tagName }) => { console.log(`第 ${times} 次重试,使用域名: ${domains}, URL: ${url}`); }, onSuccess: ({ domains, url, tagName }) => { console.log(`重试成功,域名: ${domains}, URL: ${url}`); }, onError: ({ domains, url, tagName }) => { console.log(`重试失败,域名: ${domains}, URL: ${url}`); }, }); ``` 回调函数参数说明: - `times`: 当前重试次数(从1开始) - `domains`: 当前使用的域名列表 - `url`: 当前请求的URL - `tagName`: 资源类型('fetch' 或 'script') ## 使用场景 ### 1. CDN 故障容错 ```javascript const retryPlugin = RetryPlugin({ retryTimes: 2, domains: [ 'https://cdn1.example.com', 'https://cdn2.example.com', 'https://cdn3.example.com' ], addQuery: true, }); ``` ### 2. 网络不稳定环境 ```javascript const retryPlugin = RetryPlugin({ retryTimes: 5, retryDelay: 2000, onRetry: ({ times }) => { console.log(`网络不稳定,第 ${times} 次重试`); }, }); ``` ### 3. 监控和日志 ```javascript const retryPlugin = RetryPlugin({ onRetry: ({ times, url }) => { // 发送重试事件到监控系统 analytics.track('resource_retry', { times, url }); }, onError: ({ url }) => { // 记录最终失败 logger.error('Resource load failed after all retries', { url }); }, }); ``` ## 注意事项 1. **性能考虑**: 过多的重试次数会增加加载时间,建议根据实际网络环境调整 2. **域名配置**: 确保 `domains` 中的域名都指向相同的资源 3. **缓存策略**: 使用 `addQuery` 时注意 CDN 的缓存策略 4. **错误处理**: 重试失败后,原始错误会被抛出,需要在上层进行错误处理 ## 错误码 插件使用标准的 Module Federation 错误码: - `RUNTIME_008`: 资源加载失败,触发重试机制