# @rsbuild/plugin-assets-retry 用于在静态资源加载失败时自动发起重试请求。

npm version license downloads

## 快速开始 ### 安装插件 你可以通过如下的命令安装插件: ```bash # npm npm add @rsbuild/plugin-assets-retry -D # yarn yarn add @rsbuild/plugin-assets-retry -D # pnpm pnpm add @rsbuild/plugin-assets-retry -D # bun bun add @rsbuild/plugin-assets-retry -D ``` ### 注册插件 你可以在 `rsbuild.config.ts` 文件中注册插件: ```ts import { pluginAssetsRetry } from '@rsbuild/plugin-assets-retry'; export default { plugins: [pluginAssetsRetry()], }; ``` ## 选项 你可以通过选项来配置资源加载失败时的重试逻辑。 - **类型:** ```ts type AssetsRetryHookContext = { times: number; domain: string; url: string; tagName: string; isAsyncChunk: boolean; }; type RuntimeRetryOptions = { type?: string[]; domain?: string[] | (() => string[]); max?: number; test?: string | ((url: string) => boolean); crossOrigin?: boolean | 'anonymous' | 'use-credentials'; delay?: number | ((context: AssetsRetryHookContext) => number); onRetry?: (context: AssetsRetryHookContext) => void; onSuccess?: (context: AssetsRetryHookContext) => void; onFail?: (context: AssetsRetryHookContext) => void; }; type AssetsRetryOptions = | ({ inlineScript?: boolean; minify?: boolean; } & RuntimeRetryOptions) | { inlineScript?: boolean; minify?: boolean; rules: RuntimeRetryOptions[]; }; ``` - **默认值:** ```ts const defaultAssetsRetryOptions = { max: 3, type: ['script', 'link', 'img'], domain: [], crossOrigin: rsbuildConfig.html.crossorigin, delay: 0, addQuery: false, inlineScript: true, minify: rsbuildConfig.mode === 'production', }; ``` ### domain - **类型:** `string[] | (() => string[])` - **默认值:** `[]` 指定资源加载失败时的重试域名列表。在 `domain` 数组中,第一项是静态资源默认所在的域名,后面几项为备用域名。当某个域名的资源请求失败时,Rsbuild 会在数组中找到该域名,并替换为数组的下一个域名。 比如: ```js // rsbuild.config.ts defineConfig({ plugins: [ pluginAssetsRetry({ domain: ['cdn1.com', 'cdn2.com', 'cdn3.com'], }), ], output: { assetPrefix: 'https://cdn1.com', // 或者 "//cdn1.com" }, }); ``` 添加以上配置后,当 `cdn1.com` 域名的资源加载失败时,请求域名会自动降级到 `cdn2.com`。 如果 `cdn2.com` 的资源也请求失败,则会继续请求 `cdn3.com`。 #### 利用字符串替换 `domain` 使用字符串替换生成重试 URL,因此支持带 `https://` 开头的完整地址,也支持 CDN 地址包含子路径前缀,例如 `https://cdn2.com/foo-path`。使用完整地址时,数组中的每一项都必须带协议。此外,`output.assetPrefix` 不能使用 `//cdn1.com` 这样的协议相对地址,否则无法通过字符串替换匹配。 ```js // rsbuild.config.ts defineConfig({ plugins: [ pluginAssetsRetry({ domain: [ 'https://cdn1.com', 'https://cdn2.com/foo-path', 'https://cdn3.com', ], }), ], output: { assetPrefix: 'https://cdn1.com', }, }); ``` #### 在运行时解析域名 当域名列表只有在浏览器中才能确定时(例如在应用启动时注入到 `window` 上),可以传入一个函数来代替静态数组。与 `onRetry` / `onFail` 回调一样,该函数会被序列化到运行时脚本中,并在重试脚本启动时于浏览器中执行,因此可以读取构建时并不存在的值: ```js // rsbuild.config.ts defineConfig({ plugins: [ pluginAssetsRetry({ // 在浏览器启动时执行,而非构建时。 domain: () => [ // 可以是 http://localhost:3000,也可以是 https://cdn1.com。 window.location.origin, 'https://cdn2.com/foo-path', 'https://cdn3.com', ], }), ], }); ``` 配合 `window` 注入的变量完成功能: ```js // rsbuild.config.ts defineConfig({ plugins: [ pluginAssetsRetry({ domain: () => { const backupDomains = window.userRegion === 'cn' ? ['https://cdn2.cn/foo-path', 'https://cdn3.cn'] : ['https://cdn2.com/foo-path', 'https://cdn3.com']; return [window.myAssetPath, ...backupDomains]; }, }), ], }); ``` 返回值会在重试脚本启动时解析一次,并在后续重试中复用(缓存)。 > [!NOTE] > 该函数必须是自包含的:它不能引用构建时的变量(这些变量在浏览器中并不存在),只能引用 `window` 等浏览器全局对象。 ### type - **类型:** `string[]` - **默认值:** `['script', 'link', 'img']` 用于指定需要进行重试的 HTML 标签类型。默认会处理 script 标签、link 标签和 img 标签,对应 JS 代码、CSS 代码和图片。 比如只对 script 标签和 link 标签进行处理: ```js pluginAssetsRetry({ type: ['script', 'link'], }); ``` ### max - **类型:** `number` - **默认值:** `3` 单个资源的最大重试次数。比如: ```js pluginAssetsRetry({ max: 5, }); ``` ### test - **类型:** `string | ((url: string) => boolean) | undefined` - **默认值:** `undefined` 匹配资源 URL 的正则表达式或函数,默认匹配所有资源。比如: ```js pluginAssetsRetry({ test: /cdn\.example\.com/, }); ``` ### crossOrigin - **类型:** `undefined | boolean | 'anonymous' | 'use-credentials'` - **默认值:** `与 html.crossorigin 一致` 在发起资源重新请求时,Rsbuild 会重新创建 `` 标签加载的资源是同步加载的,如果进行重试无法保证资源加载的顺序,因此 Assets Retry 插件不会对同步加载的 script 标签进行重试。只会对 async/defer 的 script 标签进行重试。 ### 模块联邦 对于模块联邦加载的远程模块,你可以使用模块联邦 2.0 的 [@module-federation/retry-plugin](https://www.npmjs.com/package/@module-federation/retry-plugin) 来实现静态资源重试。 ### 微前端 如果你的工程是微前端应用(比如 Garfish 子应用),那么 Assets Retry 插件可能无法生效,因为微前端子应用通常不是基于 `
+ <%= htmlPlugin.tags.bodyTags %> ``` #### 在 HTML 模板中识别重试脚本 Assets Retry 插件为重试脚本添加了唯一的 `data-rsbuild-assets-retry` 属性,使你可以在自定义 HTML 模板中轻松识别它们。 你可以导入属性常量: ```js import { ASSETS_RETRY_DATA_ATTRIBUTE } from '@rsbuild/plugin-assets-retry'; ``` 属性值包括: - `"inline"` 用于内联脚本(当 `inlineScript: true` 时) - `"external"` 用于外部脚本(当 `inlineScript: false` 时) 在 HTML 模板中的使用示例: ```html <%= htmlWebpackPlugin.tags.headTags.filter(tag => tag.attributes['data-rsbuild-assets-retry'] === 'inline') %> <%= htmlWebpackPlugin.tags.headTags.filter(tag => !tag.attributes['data-rsbuild-assets-retry']) %> ``` 这允许你将重试脚本放置在 HTML 头部的顶部以获得最佳的加载顺序。 ## License [MIT](./LICENSE).