Assets Retry 插件
Assets Retry 插件用于在静态资源加载失败时自动发起重试请求。
快速开始
安装插件
你可以通过如下的命令安装插件:
npm add @rsbuild/plugin-assets-retry -D
注册插件
你可以在 rsbuild.config.ts
文件中注册插件:
rsbuild.config.ts
import { pluginAssetsRetry } from '@rsbuild/plugin-assets-retry';
export default {
plugins: [pluginAssetsRetry()],
};
选项
你可以通过选项来配置资源加载失败时的重试逻辑。
type AssetsRetryHookContext = {
times: number;
domain: string;
url: string;
tagName: string;
isAsyncChunk: boolean;
};
type AssetsRetryOptions = {
type?: string[];
domain?: string[];
max?: number;
test?: string | ((url: string) => boolean);
crossOrigin?: boolean | 'anonymous' | 'use-credentials';
inlineScript?: boolean;
onRetry?: (context: AssetsRetryHookContext) => void;
onSuccess?: (context: AssetsRetryHookContext) => void;
onFail?: (context: AssetsRetryHookContext) => void;
};
const defaultOptions = {
type: ['script', 'link', 'img'],
domain: [],
max: 3,
test: '',
crossOrigin: false,
onRetry: () => {},
onSuccess: () => {},
onFail: () => {},
};
domain
指定资源加载失败时的重试域名列表。在 domain
数组中,第一项是当前使用的域名,后面几项为备用域名。当某个域名的资源请求失败时,Rsbuild 会在数组中找到该域名,并替换为数组的下一个域名。
比如:
pluginAssetsRetry({
domain: ['https://cdn1.com', 'https://cdn2.com', 'https://cdn3.com'],
});
添加以上配置后,当 cdn1.com
域名的资源加载失败时,请求域名会自动降级到 cdn2.com
。
如果 cdn2.com
的资源也请求失败,则会继续请求 cdn3.com
。
type
- 类型:
string[]
- 默认值:
['script', 'link', 'img']
用于指定需要进行重试的 HTML 标签类型。默认会处理 script 标签、link 标签和 img 标签,对应 JS 代码、CSS 代码和图片。
比如只对 script 标签和 link 标签进行处理:
pluginAssetsRetry({
type: ['script', 'link'],
});
max
单个资源的最大重试次数。比如:
pluginAssetsRetry({
max: 5,
});
test
- 类型:
string | ((url: string) => boolean) | undefined
- 默认值:
undefined
匹配资源 URL 的正则表达式或函数,默认匹配所有资源。比如:
pluginAssetsRetry({
test: /cdn\.example\.com/,
});
crossOrigin
- 类型:
undefined | boolean | 'anonymous' | 'use-credentials'
- 默认值:
与 html.crossorigin 一致
在发起资源重新请求时,Rsbuild 会重新创建 <script>
标签,此选项可以设置这些标签的 crossorigin
属性。
默认情况下,crossOrigin
的值会与 html.crossorigin
配置项保持一致,无须额外配置。如果你需要对重新创建的标签进行单独配置,可以使用该选项,比如:
pluginAssetsRetry({
crossOrigin: true,
});
onRetry
- 类型:
undefined | (context: AssetsRetryHookContext) => void
资源重试时的回调函数。比如:
pluginAssetsRetry({
onRetry: ({ times, domain, url, tagName, isAsyncChunk }) => {
console.log(
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
);
},
});
onSuccess
- 类型:
undefined | (context: AssetsRetryHookContext) => void
资源重试成功时的回调函数。比如:
pluginAssetsRetry({
onSuccess: ({ times, domain, url, tagName, isAsyncChunk }) => {
console.log(
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
);
},
});
onFail
- 类型:
undefined | (context: AssetsRetryHookContext) => void
资源重试超过最大重试次数时的回调函数。比如:
pluginAssetsRetry({
onFail: ({ times, domain, url, tagName, isAsyncChunk }) => {
console.log(
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
);
},
});
addQuery
type AddQuery =
| boolean
| ((context: { times: number; originalQuery: string }) => string);
是否在资源重试时添加 query,这样可以避免被浏览器、CDN 缓存影响到重试的结果。
当设置为 true
时,请求时会在 query 中添加 retry=${times}
,按照 retry=1
,retry=2
,retry=3
依次请求,比如:
-
假设请求的静态资源为 https://js.cdn.net/foo.js
,请求失败后会自动重试 https://js.cdn.net/foo.js?retry=${times}
-
假设请求的静态资源为 https://js.cdn.net/foo.js?version=1
,请求失败后会自动重试 https://js.cdn.net/foo.js?version=1&retry=${times}
当你想要自定义 query 时,可以传入一个函数,比如:
pluginAssetsRetry({
addQuery: ({ times }) => {
return times === 3
? `?retryCount=${times}&isLast=1`
: `?retryCount=${times}`;
},
});
- 示例: 当请求的某些资源中含有 query 时,可以使用
originalQuery
读取:
pluginAssetsRetry({
addQuery: ({ times, originalQuery }) => {
const query =
times === 3 ? `retryCount=${times}&isLast=1` : `retryCount=${times}`;
return originalQuery ? `${originalQuery}&${query}` : `?${query}`;
},
});
inlineScript
是否将 Assets Retry 插件的运行时 JavaScript 代码内联到 HTML 文件中。
如果你不希望在 HTML 文件中插入相关代码,可以将 inlineScript
设置为 false
:
pluginAssetsRetry({
inlineScript: false,
});
添加以上配置后,Assets Retry 插件的运行时代码会被抽取为一个独立的 assets-retry.[version].js
文件,并输出到产物目录下。
这种方式的弊端在于,assets-retry.[version].js
自身有加载失败的可能性。如果出现这种情况,静态资源重试的逻辑就无法生效。因此,我们更推荐将运行时代码内联到 HTML 文件中。
minify
- 类型:
boolean
- 默认值:
process.env.NODE_ENV === 'production'
是否对运行时 JavaScript 代码开启代码压缩。
默认情况下,会受到 output.minify 配置的影响。
pluginAssetsRetry({
minify: true,
});
注意事项
当你使用 Assets Retry 插件时,Rsbuild 会向 HTML 中注入一段运行时代码,并将 Assets Retry 插件配置的内容序列化,插入到这段代码中,因此你需要注意:
- 避免在 Assets Retry 插件中配置敏感信息,比如内部使用的 token。
- 避免在
onRetry
,onSuccess
,onFail
中引用函数外部的变量或方法。
- 避免在
onRetry
,onSuccess
,onFail
中使用有兼容性问题的语法,因为这些函数会被直接内联到 HTML 中。
以下是一个错误示例:
import { someMethod } from 'utils';
pluginAssetsRetry({
onRetry() {
// 错误用法,包含了敏感信息
const privateToken = 'a-private-token';
// 错误用法,使用了外部的方法
someMethod(privateToken);
},
});
使用限制
以下场景 Assets Retry 插件可能无法生效:
模块联邦
对于模块联邦加载的远程模块,你可以使用模块联邦 2.0 的 @module-federation/retry-plugin 来实现静态资源重试。
微前端
如果你的工程是微前端应用(比如 Garfish 子应用),那么 Assets Retry 插件可能无法生效,因为微前端子应用通常不是基于 <script>
标签直接加载的。
如果你需要对微前端场景的资源加载进行重试,请联系微前端框架的开发者,以寻找相应的解决方案。
自定义模版中的资源
Assets Retry 插件通过监听页面 error 事件来获悉当前资源是否加载失败需要重试。因此,如果自定义模版中的资源执行早于 Assets Retry 插件,那 Assets Retry 插件无法监听到该资源加载失败的事件,retry 无法对其生效。
如果想要 Assets Retry 插件对自定义模版中的资源生效,可参考 自定义插入示例 来修改 html.inject 配置和自定义模版。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>custom template</title>
+ <%= htmlPlugin.tags.headTags %>
<script src="https://example.com/assets/a.js"></script>
</head>
<body>
<div id="root" />
+ <%= htmlPlugin.tags.bodyTags %>
</body>
</html>