@rsbuild/plugin-assets-retry 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,33 +59,43 @@ type AssetsRetryHookContext = {
59
59
  isAsyncChunk: boolean;
60
60
  };
61
61
 
62
- type AssetsRetryOptions = {
62
+ type RuntimeRetryOptions = {
63
63
  type?: string[];
64
64
  domain?: string[];
65
65
  max?: number;
66
- test?: string | ((url: string) => boolean);
66
+ test?: string | RegExp | ((url: string) => boolean);
67
67
  crossOrigin?: boolean | 'anonymous' | 'use-credentials';
68
- inlineScript?: boolean;
69
68
  delay?: number | ((context: AssetsRetryHookContext) => number);
70
69
  onRetry?: (context: AssetsRetryHookContext) => void;
71
70
  onSuccess?: (context: AssetsRetryHookContext) => void;
72
71
  onFail?: (context: AssetsRetryHookContext) => void;
73
72
  };
73
+
74
+ type AssetsRetryOptions =
75
+ | ({
76
+ inlineScript?: boolean;
77
+ minify?: boolean;
78
+ } & RuntimeRetryOptions)
79
+ | {
80
+ inlineScript?: boolean;
81
+ minify?: boolean;
82
+ rules: RuntimeRetryOptions[];
83
+ };
74
84
  ```
75
85
 
76
86
  - **Default:**
77
87
 
78
88
  ```ts
79
89
  const defaultAssetsRetryOptions = {
90
+ max: 3,
80
91
  type: ['script', 'link', 'img'],
81
92
  domain: [],
82
- max: 3,
83
- test: '',
84
93
  crossOrigin: false,
94
+ test: '',
85
95
  delay: 0,
86
- onRetry: () => {},
87
- onSuccess: () => {},
88
- onFail: () => {},
96
+ addQuery: false,
97
+ inlineScript: true,
98
+ minify: rsbuildConfig.mode === 'production',
89
99
  };
90
100
  ```
91
101
 
@@ -242,7 +252,7 @@ When set to `true`, `retry=${times}` will be added to the query when requesting,
242
252
 
243
253
  When you want to customize query, you can pass a function, for example:
244
254
 
245
- - **Example:** All assets requested do not contain query:
255
+ - **Example 1:** All assets requested do not contain query:
246
256
 
247
257
  ```js
248
258
  pluginAssetsRetry({
@@ -254,7 +264,7 @@ pluginAssetsRetry({
254
264
  });
255
265
  ```
256
266
 
257
- - **Example:** If there is a query in some of the requested assets, you can read it with `originalQuery`:
267
+ - **Example 2:** If there is a query in some of the requested assets, you can read it with `originalQuery`:
258
268
 
259
269
  ```js
260
270
  pluginAssetsRetry({
@@ -325,6 +335,80 @@ pluginAssetsRetry({
325
335
  });
326
336
  ```
327
337
 
338
+ ### rules
339
+
340
+ - **Type:** `RuntimeRetryOptions[]`
341
+ - **Default:** `undefined`
342
+
343
+ Configure multiple retry rules with different options. Each rule will be evaluated in order, and the first matching rule will be used for retry logic. This is useful when you have different retry requirements for different types of assets or domains.
344
+
345
+ When using `rules`, the plugin will:
346
+
347
+ 1. Check each rule in order by `test` `domain` `type`
348
+
349
+ 2. If the rule is matched, the rule's configuration will be used to retry
350
+
351
+ 3. If no rule is matched, the resource will not be retried
352
+
353
+ Each rule supports all the same options as the top-level configuration, including `type`, `domain`, `max`, `test`, `crossOrigin`, `delay`, `onRetry`, `onSuccess`, and `onFail`.
354
+
355
+ - **Example 1:** Different retry strategies for different CDNs:
356
+
357
+ ```js
358
+ pluginAssetsRetry({
359
+ rules: [
360
+ {
361
+ // Rule for primary CDN
362
+ test: /cdn1\.example\.com/,
363
+ domain: ['cdn1.example.com', 'cdn1-backup.example.com'],
364
+ max: 3,
365
+ delay: 1000,
366
+ },
367
+ {
368
+ // Rule for secondary CDN with more retries
369
+ test: /cdn2\.example\.com/,
370
+ domain: ['cdn2.example.com', 'cdn2-backup.example.com'],
371
+ max: 5,
372
+ delay: 500,
373
+ },
374
+ {
375
+ // Default rule for other assets
376
+ domain: ['default.example.com', 'default-backup.example.com'],
377
+ max: 2,
378
+ },
379
+ ],
380
+ });
381
+ ```
382
+
383
+ - **Example 2:** Different retry strategies for different asset types:
384
+
385
+ ```js
386
+ pluginAssetsRetry({
387
+ rules: [
388
+ {
389
+ // Critical JavaScript files get more retries
390
+ type: ['script'],
391
+ // Or test: /\.js$/,
392
+ max: 5,
393
+ delay: 1000,
394
+ onFail: ({ url }) => console.error(`Critical JS failed: ${url}`),
395
+ },
396
+ {
397
+ // CSS files get fewer retries
398
+ test: /\.css$/,
399
+ max: 2,
400
+ delay: 500,
401
+ },
402
+ {
403
+ // Images get minimal retries
404
+ test: /\.(png|jpg|gif|svg)$/,
405
+ max: 1,
406
+ delay: 0,
407
+ },
408
+ ],
409
+ });
410
+ ```
411
+
328
412
  ## Notes
329
413
 
330
414
  When you use Assets Retry plugin, the Rsbuild injects some runtime code into the HTML and [Rspack Runtime](https://rspack.dev/misc/glossary#runtime), then serializes the Assets Retry plugin config, inserting it into the runtime code. Therefore, you need to be aware of the following:
@@ -389,6 +473,32 @@ If you want Assets Retry plugin to work on resources in custom templates, you ca
389
473
  </html>
390
474
  ```
391
475
 
476
+ #### Identifying retry scripts in HTML templates
477
+
478
+ The Assets Retry plugin adds a unique `data-rsbuild-assets-retry` attribute to retry scripts, allowing you to easily identify them in custom HTML templates.
479
+
480
+ You can import the attribute constant:
481
+
482
+ ```js
483
+ import { ASSETS_RETRY_DATA_ATTRIBUTE } from '@rsbuild/plugin-assets-retry';
484
+ ```
485
+
486
+ The attribute values are:
487
+ - `"inline"` for inline scripts (when `inlineScript: true`)
488
+ - `"external"` for external scripts (when `inlineScript: false`)
489
+
490
+ Example usage in HTML templates:
491
+
492
+ ```html
493
+ <!-- Filter retry scripts -->
494
+ <%= htmlWebpackPlugin.tags.headTags.filter(tag => tag.attributes['data-rsbuild-assets-retry'] === 'inline') %>
495
+
496
+ <!-- Filter non-retry scripts -->
497
+ <%= htmlWebpackPlugin.tags.headTags.filter(tag => !tag.attributes['data-rsbuild-assets-retry']) %>
498
+ ```
499
+
500
+ This allows you to place retry scripts at the top of your HTML head for optimal loading order.
501
+
392
502
  ## License
393
503
 
394
504
  [MIT](./LICENSE).
package/README.zh-CN.md CHANGED
@@ -57,33 +57,43 @@ type AssetsRetryHookContext = {
57
57
  isAsyncChunk: boolean;
58
58
  };
59
59
 
60
- type AssetsRetryOptions = {
60
+ type RuntimeRetryOptions = {
61
61
  type?: string[];
62
62
  domain?: string[];
63
63
  max?: number;
64
64
  test?: string | ((url: string) => boolean);
65
65
  crossOrigin?: boolean | 'anonymous' | 'use-credentials';
66
- inlineScript?: boolean;
67
66
  delay?: number | ((context: AssetsRetryHookContext) => number);
68
67
  onRetry?: (context: AssetsRetryHookContext) => void;
69
68
  onSuccess?: (context: AssetsRetryHookContext) => void;
70
69
  onFail?: (context: AssetsRetryHookContext) => void;
71
70
  };
71
+
72
+ type AssetsRetryOptions =
73
+ | ({
74
+ inlineScript?: boolean;
75
+ minify?: boolean;
76
+ } & RuntimeRetryOptions)
77
+ | {
78
+ inlineScript?: boolean;
79
+ minify?: boolean;
80
+ rules: RuntimeRetryOptions[];
81
+ };
72
82
  ```
73
83
 
74
84
  - **默认值:**
75
85
 
76
86
  ```ts
77
- const defaultOptions = {
87
+ const defaultAssetsRetryOptions = {
88
+ max: 3,
78
89
  type: ['script', 'link', 'img'],
79
90
  domain: [],
80
- max: 3,
81
- test: '',
82
91
  crossOrigin: false,
92
+ test: '',
83
93
  delay: 0,
84
- onRetry: () => {},
85
- onSuccess: () => {},
86
- onFail: () => {},
94
+ addQuery: false,
95
+ inlineScript: true,
96
+ minify: rsbuildConfig.mode === 'production',
87
97
  };
88
98
  ```
89
99
 
@@ -240,7 +250,7 @@ type AddQuery =
240
250
 
241
251
  当你想要自定义 query 时,可以传入一个函数,比如:
242
252
 
243
- - **示例:** 请求的所有资源都不含 query:
253
+ - **示例 1:** 请求的所有资源都不含 query:
244
254
 
245
255
  ```js
246
256
  pluginAssetsRetry({
@@ -252,7 +262,7 @@ pluginAssetsRetry({
252
262
  });
253
263
  ```
254
264
 
255
- - **示例:** 当请求的某些资源中含有 query 时,可以使用 `originalQuery` 读取:
265
+ - **示例 2:** 当请求的某些资源中含有 query 时,可以使用 `originalQuery` 读取:
256
266
 
257
267
  ```js
258
268
  pluginAssetsRetry({
@@ -323,6 +333,80 @@ pluginAssetsRetry({
323
333
  });
324
334
  ```
325
335
 
336
+ ### rules
337
+
338
+ - **类型:** `RuntimeRetryOptions[]`
339
+ - **默认值:** `undefined`
340
+
341
+ 配置多个重试规则,每个规则可以有不同的选项。规则会按顺序进行评估,第一个匹配的规则将用于重试逻辑。这在你对不同类型的资源或域名有不同的重试需求时非常有用。
342
+
343
+ 使用 `rules` 时,插件会:
344
+
345
+ 1. 按顺序通过 `test` `domain` `type` 检查每个规则
346
+
347
+ 2. 如果匹配到规则,会使用规则的配置进行重试
348
+
349
+ 3. 如果没有匹配到规则,则不会重试该资源
350
+
351
+ 每个规则支持与顶层配置相同的所有选项,包括 `type`、`domain`、`test`、`max`、`crossOrigin`、`delay`、`onRetry`、`onSuccess` 和 `onFail`。
352
+
353
+ - **示例 1:** 不同 CDN 的不同重试策略:
354
+
355
+ ```js
356
+ pluginAssetsRetry({
357
+ rules: [
358
+ {
359
+ // 主 CDN 的规则
360
+ test: /cdn1\.example\.com/,
361
+ domain: ['cdn1.example.com', 'cdn1-backup.example.com'],
362
+ max: 3,
363
+ delay: 1000,
364
+ },
365
+ {
366
+ // 次要 CDN 的规则,更多重试次数
367
+ test: /cdn2\.example\.com/,
368
+ domain: ['cdn2.example.com', 'cdn2-backup.example.com'],
369
+ max: 5,
370
+ delay: 500,
371
+ },
372
+ {
373
+ // 其他资源的默认规则
374
+ domain: ['default.example.com', 'default-backup.example.com'],
375
+ max: 2,
376
+ },
377
+ ],
378
+ });
379
+ ```
380
+
381
+ - **示例 2:** 不同资源类型的不同重试策略:
382
+
383
+ ```js
384
+ pluginAssetsRetry({
385
+ rules: [
386
+ {
387
+ // 关键 JavaScript 文件获得更多重试次数
388
+ test: /\.js$/,
389
+ // 或者 type: ['script'],
390
+ max: 5,
391
+ delay: 1000,
392
+ onFail: ({ url }) => console.error(`关键 JS 失败: ${url}`),
393
+ },
394
+ {
395
+ // CSS 文件获得较少的重试次数
396
+ test: /\.css$/,
397
+ max: 2,
398
+ delay: 500,
399
+ },
400
+ {
401
+ // 图片获得最少的重试次数
402
+ test: /\.(png|jpg|gif|svg)$/,
403
+ max: 1,
404
+ delay: 0,
405
+ },
406
+ ],
407
+ });
408
+ ```
409
+
326
410
  ## 注意事项
327
411
 
328
412
  当你使用 Assets Retry 插件时,Rsbuild 会分别向 HTML 和 [Rspack Runtime](https://rspack.dev/zh/misc/glossary#runtime) 中注入运行时代码,并将 Assets Retry 插件配置的内容序列化后插入到这些代码中,因此你需要注意:
@@ -387,6 +471,32 @@ Assets Retry 插件通过监听页面 error 事件来获悉当前资源是否加
387
471
  </html>
388
472
  ```
389
473
 
474
+ #### 在 HTML 模板中识别重试脚本
475
+
476
+ Assets Retry 插件为重试脚本添加了唯一的 `data-rsbuild-assets-retry` 属性,使您可以在自定义 HTML 模板中轻松识别它们。
477
+
478
+ 您可以导入属性常量:
479
+
480
+ ```js
481
+ import { ASSETS_RETRY_DATA_ATTRIBUTE } from '@rsbuild/plugin-assets-retry';
482
+ ```
483
+
484
+ 属性值包括:
485
+ - `"inline"` 用于内联脚本(当 `inlineScript: true` 时)
486
+ - `"external"` 用于外部脚本(当 `inlineScript: false` 时)
487
+
488
+ 在 HTML 模板中的使用示例:
489
+
490
+ ```html
491
+ <!-- 筛选重试脚本 -->
492
+ <%= htmlWebpackPlugin.tags.headTags.filter(tag => tag.attributes['data-rsbuild-assets-retry'] === 'inline') %>
493
+
494
+ <!-- 筛选非重试脚本 -->
495
+ <%= htmlWebpackPlugin.tags.headTags.filter(tag => !tag.attributes['data-rsbuild-assets-retry']) %>
496
+ ```
497
+
498
+ 这允许您将重试脚本放置在 HTML 头部的顶部以获得最佳的加载顺序。
499
+
390
500
  ## License
391
501
 
392
502
  [MIT](./LICENSE).
package/dist/index.cjs CHANGED
@@ -170,6 +170,7 @@ var __webpack_exports__ = {};
170
170
  __webpack_require__.r(__webpack_exports__);
171
171
  __webpack_require__.d(__webpack_exports__, {
172
172
  pluginAssetsRetry: ()=>pluginAssetsRetry,
173
+ ASSETS_RETRY_DATA_ATTRIBUTE: ()=>ASSETS_RETRY_DATA_ATTRIBUTE,
173
174
  PLUGIN_ASSETS_RETRY_NAME: ()=>PLUGIN_ASSETS_RETRY_NAME
174
175
  });
175
176
  const external_node_fs_namespaceObject = require("node:fs");
@@ -249,8 +250,9 @@ var __webpack_exports__ = {};
249
250
  }
250
251
  const src_dirname = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__));
251
252
  const PLUGIN_ASSETS_RETRY_NAME = 'rsbuild:assets-retry';
252
- function getRuntimeOptions(userOptions) {
253
- const { inlineScript, minify, ...restOptions } = userOptions;
253
+ const ASSETS_RETRY_DATA_ATTRIBUTE = 'data-rsbuild-assets-retry';
254
+ function getRuntimeOptions(userOptions, defaultCrossOrigin) {
255
+ const { inlineScript, minify, ...runtimeOptions } = userOptions;
254
256
  const defaultOptions = {
255
257
  max: 3,
256
258
  type: [
@@ -259,18 +261,27 @@ var __webpack_exports__ = {};
259
261
  'img'
260
262
  ],
261
263
  domain: [],
262
- crossOrigin: false,
264
+ crossOrigin: defaultCrossOrigin,
263
265
  delay: 0,
264
266
  addQuery: false
265
267
  };
266
- const result = {
267
- ...defaultOptions,
268
- ...restOptions
269
- };
270
- if (!Array.isArray(result.type) || 0 === result.type.length) result.type = defaultOptions.type;
271
- if (!Array.isArray(result.domain) || 0 === result.domain.length) result.domain = defaultOptions.domain;
272
- if (Array.isArray(result.domain)) result.domain = result.domain.filter(Boolean);
273
- return result;
268
+ function normalizeOption(options) {
269
+ const result = {
270
+ ...defaultOptions,
271
+ ...options
272
+ };
273
+ if (!Array.isArray(result.type) || 0 === result.type.length) result.type = defaultOptions.type;
274
+ if (!Array.isArray(result.domain) || 0 === result.domain.length) result.domain = defaultOptions.domain;
275
+ if (Array.isArray(result.domain)) result.domain = result.domain.filter(Boolean);
276
+ return result;
277
+ }
278
+ if ('rules' in runtimeOptions) {
279
+ const result = runtimeOptions.rules.map((i)=>normalizeOption(i));
280
+ return result;
281
+ }
282
+ return [
283
+ normalizeOption(runtimeOptions)
284
+ ];
274
285
  }
275
286
  async function getRetryCode(runtimeOptions, minify) {
276
287
  const filename = 'initialChunkRetry';
@@ -284,27 +295,25 @@ var __webpack_exports__ = {};
284
295
  const { inlineScript = true } = userOptions;
285
296
  const getScriptPath = (environment)=>{
286
297
  const distDir = environment.config.output.distPath.js;
287
- return external_node_path_default().posix.join(distDir, "assets-retry.1-3-0.js");
298
+ return external_node_path_default().posix.join(distDir, "assets-retry.1-4-0.js");
288
299
  };
289
- const normalizeOptions = (config)=>{
290
- const options = {
291
- ...userOptions
300
+ const getDefaultValueFromRsbuildConfig = (config)=>{
301
+ var _config_output_minify;
302
+ const minify = 'boolean' == typeof config.output.minify ? config.output.minify : null == (_config_output_minify = config.output.minify) ? void 0 : _config_output_minify.js;
303
+ return {
304
+ crossorigin: config.html.crossorigin,
305
+ minify: Boolean(minify) && 'production' === config.mode
292
306
  };
293
- if (void 0 === options.crossOrigin) options.crossOrigin = config.html.crossorigin;
294
- if (void 0 === options.minify) {
295
- var _config_output_minify;
296
- const minify = 'boolean' == typeof config.output.minify ? config.output.minify : null == (_config_output_minify = config.output.minify) ? void 0 : _config_output_minify.js;
297
- options.minify = minify && 'production' === config.mode;
298
- }
299
- return options;
300
307
  };
301
308
  if (inlineScript) api.modifyHTMLTags(async ({ headTags, bodyTags }, { environment })=>{
302
- const options = normalizeOptions(environment.config);
303
- const runtimeOptions = getRuntimeOptions(options);
304
- const code = await getRetryCode(runtimeOptions, options.minify);
309
+ const { minify, crossorigin } = getDefaultValueFromRsbuildConfig(environment.config);
310
+ const runtimeOptions = getRuntimeOptions(userOptions, crossorigin);
311
+ const code = await getRetryCode(runtimeOptions, minify);
305
312
  headTags.unshift({
306
313
  tag: "script",
307
- attrs: {},
314
+ attrs: {
315
+ [ASSETS_RETRY_DATA_ATTRIBUTE]: 'inline'
316
+ },
308
317
  children: code
309
318
  });
310
319
  return {
@@ -319,7 +328,8 @@ var __webpack_exports__ = {};
319
328
  headTags.unshift({
320
329
  tag: "script",
321
330
  attrs: {
322
- src: url
331
+ src: url,
332
+ [ASSETS_RETRY_DATA_ATTRIBUTE]: 'external'
323
333
  }
324
334
  });
325
335
  return {
@@ -331,30 +341,32 @@ var __webpack_exports__ = {};
331
341
  stage: 'additional'
332
342
  }, async ({ sources, compilation, environment })=>{
333
343
  const scriptPath = getScriptPath(environment);
334
- const options = normalizeOptions(environment.config);
335
- const runtimeOptions = getRuntimeOptions(options);
336
- const code = await getRetryCode(runtimeOptions, options.minify);
344
+ const { crossorigin, minify } = getDefaultValueFromRsbuildConfig(environment.config);
345
+ const runtimeOptions = getRuntimeOptions(userOptions, crossorigin);
346
+ const code = await getRetryCode(runtimeOptions, minify);
337
347
  compilation.emitAsset(scriptPath, new sources.RawSource(code));
338
348
  });
339
349
  }
340
350
  api.modifyBundlerChain(async (chain, { environment })=>{
341
351
  const { config, htmlPaths } = environment;
342
352
  if (!userOptions || 0 === Object.keys(htmlPaths).length) return;
343
- const options = normalizeOptions(config);
344
- const runtimeOptions = getRuntimeOptions(options);
353
+ const { crossorigin, minify } = getDefaultValueFromRsbuildConfig(config);
354
+ const runtimeOptions = getRuntimeOptions(userOptions, crossorigin);
345
355
  const isRspack = 'rspack' === api.context.bundlerType;
346
356
  chain.plugin('async-chunk-retry').use(AsyncChunkRetryPlugin, [
347
357
  runtimeOptions,
348
358
  isRspack,
349
- options.minify
359
+ minify
350
360
  ]);
351
361
  });
352
362
  }
353
363
  });
354
364
  })();
365
+ exports.ASSETS_RETRY_DATA_ATTRIBUTE = __webpack_exports__.ASSETS_RETRY_DATA_ATTRIBUTE;
355
366
  exports.PLUGIN_ASSETS_RETRY_NAME = __webpack_exports__.PLUGIN_ASSETS_RETRY_NAME;
356
367
  exports.pluginAssetsRetry = __webpack_exports__.pluginAssetsRetry;
357
368
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
369
+ "ASSETS_RETRY_DATA_ATTRIBUTE",
358
370
  "PLUGIN_ASSETS_RETRY_NAME",
359
371
  "pluginAssetsRetry"
360
372
  ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { CrossOrigin as CrossOrigin_2 } from '@rsbuild/core';
2
2
  import type { RsbuildPlugin } from '@rsbuild/core';
3
3
 
4
+ export declare const ASSETS_RETRY_DATA_ATTRIBUTE = "data-rsbuild-assets-retry";
5
+
4
6
  declare type AssetsRetryHookContext_2 = {
5
7
  url: string;
6
8
  times: number;
@@ -26,7 +28,9 @@ export declare const PLUGIN_ASSETS_RETRY_NAME = "rsbuild:assets-retry";
26
28
 
27
29
  export declare const pluginAssetsRetry: (userOptions?: PluginAssetsRetryOptions) => RsbuildPlugin;
28
30
 
29
- export declare type PluginAssetsRetryOptions = RuntimeRetryOptions & CompileTimeRetryOptions;
31
+ export declare type PluginAssetsRetryOptions = (RuntimeRetryOptions & CompileTimeRetryOptions) | ({
32
+ rules: RuntimeRetryOptions[];
33
+ } & CompileTimeRetryOptions);
30
34
 
31
35
  declare type RuntimeRetryOptions = RuntimeRetryOptionsWithDefaultValue & RuntimeRetryOptionsWithoutDefaultValue;
32
36
 
@@ -78,7 +82,7 @@ declare type RuntimeRetryOptionsWithoutDefaultValue = {
78
82
  /**
79
83
  * The test function of the asset to be retried.
80
84
  */
81
- test?: string | ((url: string) => boolean);
85
+ test?: string | RegExp | ((url: string) => boolean);
82
86
  /**
83
87
  * The callback function when the asset is failed to be retried.
84
88
  */
package/dist/index.js CHANGED
@@ -225,8 +225,9 @@ class AsyncChunkRetryPlugin {
225
225
  }
226
226
  const src_dirname = node_path.dirname(fileURLToPath(import.meta.url));
227
227
  const PLUGIN_ASSETS_RETRY_NAME = 'rsbuild:assets-retry';
228
- function getRuntimeOptions(userOptions) {
229
- const { inlineScript, minify, ...restOptions } = userOptions;
228
+ const ASSETS_RETRY_DATA_ATTRIBUTE = 'data-rsbuild-assets-retry';
229
+ function getRuntimeOptions(userOptions, defaultCrossOrigin) {
230
+ const { inlineScript, minify, ...runtimeOptions } = userOptions;
230
231
  const defaultOptions = {
231
232
  max: 3,
232
233
  type: [
@@ -235,18 +236,27 @@ function getRuntimeOptions(userOptions) {
235
236
  'img'
236
237
  ],
237
238
  domain: [],
238
- crossOrigin: false,
239
+ crossOrigin: defaultCrossOrigin,
239
240
  delay: 0,
240
241
  addQuery: false
241
242
  };
242
- const result = {
243
- ...defaultOptions,
244
- ...restOptions
245
- };
246
- if (!Array.isArray(result.type) || 0 === result.type.length) result.type = defaultOptions.type;
247
- if (!Array.isArray(result.domain) || 0 === result.domain.length) result.domain = defaultOptions.domain;
248
- if (Array.isArray(result.domain)) result.domain = result.domain.filter(Boolean);
249
- return result;
243
+ function normalizeOption(options) {
244
+ const result = {
245
+ ...defaultOptions,
246
+ ...options
247
+ };
248
+ if (!Array.isArray(result.type) || 0 === result.type.length) result.type = defaultOptions.type;
249
+ if (!Array.isArray(result.domain) || 0 === result.domain.length) result.domain = defaultOptions.domain;
250
+ if (Array.isArray(result.domain)) result.domain = result.domain.filter(Boolean);
251
+ return result;
252
+ }
253
+ if ('rules' in runtimeOptions) {
254
+ const result = runtimeOptions.rules.map((i)=>normalizeOption(i));
255
+ return result;
256
+ }
257
+ return [
258
+ normalizeOption(runtimeOptions)
259
+ ];
250
260
  }
251
261
  async function getRetryCode(runtimeOptions, minify) {
252
262
  const filename = 'initialChunkRetry';
@@ -260,27 +270,25 @@ const pluginAssetsRetry = (userOptions = {})=>({
260
270
  const { inlineScript = true } = userOptions;
261
271
  const getScriptPath = (environment)=>{
262
272
  const distDir = environment.config.output.distPath.js;
263
- return node_path.posix.join(distDir, "assets-retry.1-3-0.js");
273
+ return node_path.posix.join(distDir, "assets-retry.1-4-0.js");
264
274
  };
265
- const normalizeOptions = (config)=>{
266
- const options = {
267
- ...userOptions
275
+ const getDefaultValueFromRsbuildConfig = (config)=>{
276
+ var _config_output_minify;
277
+ const minify = 'boolean' == typeof config.output.minify ? config.output.minify : null == (_config_output_minify = config.output.minify) ? void 0 : _config_output_minify.js;
278
+ return {
279
+ crossorigin: config.html.crossorigin,
280
+ minify: Boolean(minify) && 'production' === config.mode
268
281
  };
269
- if (void 0 === options.crossOrigin) options.crossOrigin = config.html.crossorigin;
270
- if (void 0 === options.minify) {
271
- var _config_output_minify;
272
- const minify = 'boolean' == typeof config.output.minify ? config.output.minify : null == (_config_output_minify = config.output.minify) ? void 0 : _config_output_minify.js;
273
- options.minify = minify && 'production' === config.mode;
274
- }
275
- return options;
276
282
  };
277
283
  if (inlineScript) api.modifyHTMLTags(async ({ headTags, bodyTags }, { environment })=>{
278
- const options = normalizeOptions(environment.config);
279
- const runtimeOptions = getRuntimeOptions(options);
280
- const code = await getRetryCode(runtimeOptions, options.minify);
284
+ const { minify, crossorigin } = getDefaultValueFromRsbuildConfig(environment.config);
285
+ const runtimeOptions = getRuntimeOptions(userOptions, crossorigin);
286
+ const code = await getRetryCode(runtimeOptions, minify);
281
287
  headTags.unshift({
282
288
  tag: "script",
283
- attrs: {},
289
+ attrs: {
290
+ [ASSETS_RETRY_DATA_ATTRIBUTE]: 'inline'
291
+ },
284
292
  children: code
285
293
  });
286
294
  return {
@@ -295,7 +303,8 @@ const pluginAssetsRetry = (userOptions = {})=>({
295
303
  headTags.unshift({
296
304
  tag: "script",
297
305
  attrs: {
298
- src: url
306
+ src: url,
307
+ [ASSETS_RETRY_DATA_ATTRIBUTE]: 'external'
299
308
  }
300
309
  });
301
310
  return {
@@ -307,24 +316,24 @@ const pluginAssetsRetry = (userOptions = {})=>({
307
316
  stage: 'additional'
308
317
  }, async ({ sources, compilation, environment })=>{
309
318
  const scriptPath = getScriptPath(environment);
310
- const options = normalizeOptions(environment.config);
311
- const runtimeOptions = getRuntimeOptions(options);
312
- const code = await getRetryCode(runtimeOptions, options.minify);
319
+ const { crossorigin, minify } = getDefaultValueFromRsbuildConfig(environment.config);
320
+ const runtimeOptions = getRuntimeOptions(userOptions, crossorigin);
321
+ const code = await getRetryCode(runtimeOptions, minify);
313
322
  compilation.emitAsset(scriptPath, new sources.RawSource(code));
314
323
  });
315
324
  }
316
325
  api.modifyBundlerChain(async (chain, { environment })=>{
317
326
  const { config, htmlPaths } = environment;
318
327
  if (!userOptions || 0 === Object.keys(htmlPaths).length) return;
319
- const options = normalizeOptions(config);
320
- const runtimeOptions = getRuntimeOptions(options);
328
+ const { crossorigin, minify } = getDefaultValueFromRsbuildConfig(config);
329
+ const runtimeOptions = getRuntimeOptions(userOptions, crossorigin);
321
330
  const isRspack = 'rspack' === api.context.bundlerType;
322
331
  chain.plugin('async-chunk-retry').use(AsyncChunkRetryPlugin, [
323
332
  runtimeOptions,
324
333
  isRspack,
325
- options.minify
334
+ minify
326
335
  ]);
327
336
  });
328
337
  }
329
338
  });
330
- export { PLUGIN_ASSETS_RETRY_NAME, pluginAssetsRetry };
339
+ export { ASSETS_RETRY_DATA_ATTRIBUTE, PLUGIN_ASSETS_RETRY_NAME, pluginAssetsRetry };
@@ -3,18 +3,17 @@
3
3
  var ERROR_PREFIX = '[@rsbuild/plugin-assets-retry] ';
4
4
  function findCurrentDomain(url, config) {
5
5
  var domains = config.domain;
6
- var domain = '';
7
- for(var i = 0; i < domains.length; i++)if (-1 !== url.indexOf(domains[i])) {
8
- domain = domains[i];
9
- break;
6
+ for(var i = 0; i < domains.length; i++){
7
+ var domain = domains[i];
8
+ if (-1 !== url.indexOf(domain)) return domain;
10
9
  }
11
- return domain || window.origin;
10
+ return window.origin;
12
11
  }
13
12
  function findNextDomain(url, config) {
14
13
  var domains = config.domain;
15
14
  var currentDomain = findCurrentDomain(url, config);
16
15
  var index = domains.indexOf(currentDomain);
17
- return domains[(index + 1) % domains.length] || url;
16
+ return -1 === index ? currentDomain : domains[(index + 1) % domains.length];
18
17
  }
19
18
  var postfixRE = /[?#].*$/;
20
19
  function cleanUrl(url) {
@@ -35,8 +34,32 @@
35
34
  function getNextRetryUrl(currRetryUrl, domain, nextDomain, existRetryTimes, originalQuery, config) {
36
35
  return cleanUrl(currRetryUrl.replace(domain, nextDomain)) + getUrlRetryQuery(existRetryTimes + 1, originalQuery, config);
37
36
  }
38
- var asyncChunkRetry_config = __RETRY_OPTIONS__;
39
- var maxRetries = asyncChunkRetry_config.max;
37
+ function _instanceof(left, right) {
38
+ if (null != right && "undefined" != typeof Symbol && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);
39
+ return left instanceof right;
40
+ }
41
+ function findMatchingRule(url, type, rules) {
42
+ for(var i = 0; i < rules.length; i++){
43
+ var rule = rules[i];
44
+ var tester = rule.test;
45
+ var shouldMatch = true;
46
+ if (_instanceof(tester, RegExp)) shouldMatch = tester.test(url);
47
+ else if ('string' == typeof tester) {
48
+ var regexp = new RegExp(tester);
49
+ shouldMatch = regexp.test(url);
50
+ } else if ('function' == typeof tester) shouldMatch = tester(url);
51
+ if (rule.domain && rule.domain.length > 0) {
52
+ var domain = findCurrentDomain(url, rule);
53
+ if (!rule.domain.includes(domain)) shouldMatch = false;
54
+ }
55
+ if (rule.type && rule.type.length > 0) {
56
+ if (!rule.type.includes(type)) shouldMatch = false;
57
+ }
58
+ if (shouldMatch) return rule;
59
+ }
60
+ return null;
61
+ }
62
+ var asyncChunkRetry_rules = __RETRY_OPTIONS__;
40
63
  var retryCollector = {};
41
64
  var retryCssCollector = {};
42
65
  var globalCurrRetrying = {};
@@ -52,13 +75,17 @@
52
75
  var originalSrcUrl = '/' === originalPublicPath[0] && '/' !== originalPublicPath[1] ? window.origin + originalPublicPath + originalScriptFilename : originalPublicPath + originalScriptFilename;
53
76
  var originalQuery = getQueryFromUrl(originalSrcUrl);
54
77
  var existRetryTimes = 0;
55
- var nextDomain = findCurrentDomain(originalSrcUrl, asyncChunkRetry_config);
78
+ var tagName = isCssAsyncChunk ? 'link' : "script";
79
+ var rule = findMatchingRule(originalSrcUrl, tagName, asyncChunkRetry_rules);
80
+ if (!rule) return null;
81
+ var nextDomain = findCurrentDomain(originalSrcUrl, rule);
56
82
  return {
57
83
  nextDomain: nextDomain,
58
- nextRetryUrl: getNextRetryUrl(originalSrcUrl, nextDomain, nextDomain, existRetryTimes, originalQuery, asyncChunkRetry_config),
84
+ nextRetryUrl: getNextRetryUrl(originalSrcUrl, nextDomain, nextDomain, existRetryTimes, originalQuery, rule),
59
85
  originalScriptFilename: originalScriptFilename,
60
86
  originalSrcUrl: originalSrcUrl,
61
- originalQuery: originalQuery
87
+ originalQuery: originalQuery,
88
+ rule: rule
62
89
  };
63
90
  }
64
91
  function asyncChunkRetry_nextRetry(chunkId, existRetryTimes, isCssAsyncChunk) {
@@ -67,17 +94,19 @@
67
94
  var nextExistRetryTimes = existRetryTimes + 1;
68
95
  if (0 === existRetryTimes || void 0 === currRetry) {
69
96
  nextRetry = initRetry(chunkId, isCssAsyncChunk);
97
+ if (!nextRetry) return null;
70
98
  if (isCssAsyncChunk) retryCssCollector[chunkId] = [];
71
99
  else retryCollector[chunkId] = [];
72
100
  } else {
73
- var originalScriptFilename = currRetry.originalScriptFilename, originalSrcUrl = currRetry.originalSrcUrl, originalQuery = currRetry.originalQuery;
74
- var nextDomain = findNextDomain(currRetry.nextDomain, asyncChunkRetry_config);
101
+ var originalScriptFilename = currRetry.originalScriptFilename, originalSrcUrl = currRetry.originalSrcUrl, originalQuery = currRetry.originalQuery, rule = currRetry.rule;
102
+ var nextDomain = findNextDomain(currRetry.nextDomain, rule);
75
103
  nextRetry = {
76
104
  nextDomain: nextDomain,
77
- nextRetryUrl: getNextRetryUrl(currRetry.nextRetryUrl, currRetry.nextDomain, nextDomain, existRetryTimes, originalQuery, asyncChunkRetry_config),
105
+ nextRetryUrl: getNextRetryUrl(currRetry.nextRetryUrl, currRetry.nextDomain, nextDomain, existRetryTimes, originalQuery, rule),
78
106
  originalScriptFilename: originalScriptFilename,
79
107
  originalSrcUrl: originalSrcUrl,
80
- originalQuery: originalQuery
108
+ originalQuery: originalQuery,
109
+ rule: rule
81
110
  };
82
111
  }
83
112
  if (isCssAsyncChunk) {
@@ -123,16 +152,19 @@
123
152
  var originalScriptFilename;
124
153
  var nextRetryUrl;
125
154
  var nextDomain;
155
+ var rule;
126
156
  var isCssAsyncChunkLoadFailed = Boolean(null == error ? void 0 : null == (_error_message = error.message) ? void 0 : _error_message.includes('CSS chunk'));
127
157
  if (isCssAsyncChunkLoadFailed) callingCounter.cssFailedCount += 1;
128
158
  var existRetryTimes = isCssAsyncChunkLoadFailed ? cssExistRetryTimes : jsExistRetryTimes;
129
159
  try {
130
160
  var retryResult = asyncChunkRetry_nextRetry(chunkId, existRetryTimes, isCssAsyncChunkLoadFailed);
161
+ if (!retryResult) throw error;
131
162
  originalScriptFilename = retryResult.originalScriptFilename;
132
163
  nextRetryUrl = retryResult.nextRetryUrl;
133
164
  nextDomain = retryResult.nextDomain;
165
+ rule = retryResult.rule;
134
166
  } catch (e) {
135
- console.error(ERROR_PREFIX, 'failed to get nextRetryUrl', e);
167
+ if (e !== error) console.error(ERROR_PREFIX, 'failed to get nextRetryUrl', e);
136
168
  throw error;
137
169
  }
138
170
  var createContext = function(times) {
@@ -145,25 +177,14 @@
145
177
  };
146
178
  };
147
179
  var context = createContext(existRetryTimes);
148
- if (existRetryTimes >= maxRetries) {
180
+ if (existRetryTimes >= rule.max) {
149
181
  var _error_message1;
150
- error.message = (null == (_error_message1 = error.message) ? void 0 : _error_message1.includes('retries:')) ? error.message : "Loading chunk ".concat(chunkId, ' from "').concat(originalScriptFilename, '" failed after ').concat(maxRetries, ' retries: "').concat(error.message, '"');
151
- if ('function' == typeof asyncChunkRetry_config.onFail) asyncChunkRetry_config.onFail(context);
182
+ error.message = (null == (_error_message1 = error.message) ? void 0 : _error_message1.includes('retries:')) ? error.message : "Loading chunk ".concat(chunkId, ' from "').concat(originalScriptFilename, '" failed after ').concat(rule.max, ' retries: "').concat(error.message, '"');
183
+ if ('function' == typeof rule.onFail) rule.onFail(context);
152
184
  throw error;
153
185
  }
154
- var tester = asyncChunkRetry_config.test;
155
- if (tester) {
156
- if ('string' == typeof tester) {
157
- var regexp = new RegExp(tester);
158
- tester = function(str) {
159
- return regexp.test(str);
160
- };
161
- }
162
- if ('function' != typeof tester || !tester(nextRetryUrl)) throw error;
163
- }
164
- if (asyncChunkRetry_config.domain && asyncChunkRetry_config.domain.length > 0 && -1 === asyncChunkRetry_config.domain.indexOf(nextDomain)) throw error;
165
- if ('function' == typeof asyncChunkRetry_config.onRetry) asyncChunkRetry_config.onRetry(context);
166
- var delayTime = 'function' == typeof asyncChunkRetry_config.delay ? asyncChunkRetry_config.delay(context) : asyncChunkRetry_config.delay;
186
+ if ('function' == typeof rule.onRetry) rule.onRetry(context);
187
+ var delayTime = 'function' == typeof rule.delay ? rule.delay(context) : rule.delay;
167
188
  var delayPromise = delayTime > 0 ? new Promise(function(resolve) {
168
189
  return setTimeout(resolve, delayTime);
169
190
  }) : Promise.resolve();
@@ -171,9 +192,9 @@
171
192
  return ensureChunk.apply(ensureChunk, args);
172
193
  }).then(function(result) {
173
194
  var isLastSuccessRetry = (null == callingCounter ? void 0 : callingCounter.count) === existRetryTimesAll + 2;
174
- if ('function' == typeof asyncChunkRetry_config.onSuccess && isLastSuccessRetry) {
195
+ if ('function' == typeof rule.onSuccess && isLastSuccessRetry) {
175
196
  var context = createContext(existRetryTimes + 1);
176
- asyncChunkRetry_config.onSuccess(context);
197
+ rule.onSuccess(context);
177
198
  }
178
199
  return result;
179
200
  });
@@ -1 +1 @@
1
- !function(){"use strict";var n="[@rsbuild/plugin-assets-retry] ";function r(n,r){for(var e=r.domain,t="",i=0;i<e.length;i++)if(-1!==n.indexOf(e[i])){t=e[i];break}return t||window.origin}var e=/[?#].*$/;function t(n,r,t,i,o,_){var a;return n.replace(r,t).replace(e,"")+(a=i+1,!0===_.addQuery?""!==o?"".concat(o,"&retry=").concat(a):"?retry=".concat(a):"function"==typeof _.addQuery?_.addQuery({times:a,originalQuery:o}):"")}var i=__RETRY_OPTIONS__,o=i.max,_={},a={},c={},l={},u=__RUNTIME_GLOBALS_ENSURE_CHUNK__,s=__RUNTIME_GLOBALS_GET_CHUNK_SCRIPT_FILENAME__,f=__RUNTIME_GLOBALS_GET_MINI_CSS_EXTRACT_FILENAME__||__RUNTIME_GLOBALS_GET_CSS_FILENAME__||function(){return null},d=__RUNTIME_GLOBALS_LOAD_SCRIPT__;function y(e){var d=Array.prototype.slice.call(arguments);d[10]||(d[10]={count:0,cssFailedCount:0});var S=d[10],R=u.apply(null,d);try{var p=s(e),E=f(e);"undefined"!=typeof window&&(p&&(window.__RB_ASYNC_CHUNKS__[p]=!0),E&&(window.__RB_ASYNC_CHUNKS__[E]=!0))}catch(r){console.error(n,"get original script or CSS filename error",r)}return S&&"number"==typeof S.count&&"number"==typeof S.cssFailedCount?(S.count+=1,R.catch(function(u){var R,p,E,U,L,m=S.count-1,g=S.cssFailedCount,v=!!(null==u||null==(R=u.message)?void 0:R.includes("CSS chunk"));v&&(S.cssFailedCount+=1);var N=v?g:m-g;try{var A=function(n,e,o){var u,d,y,S=o?null==(u=a[n])?void 0:u[e]:null==(d=_[n])?void 0:d[e],R=e+1;if(0===e||void 0===S)y=function(n,e){var o,_=e?f(n):s(n);if(!_)throw Error("only support cssExtract");var a=__RUNTIME_GLOBALS_PUBLIC_PATH__,c="/"===a[0]&&"/"!==a[1]?window.origin+a+_:a+_,l=(o=c.split("?")[1])?"?".concat(o.split("#")[0]):"",u=r(c,i);return{nextDomain:u,nextRetryUrl:t(c,u,u,0,l,i),originalScriptFilename:_,originalSrcUrl:c,originalQuery:l}}(n,o),o?a[n]=[]:_[n]=[];else{var p,E,U,L,m=S.originalScriptFilename,g=S.originalSrcUrl,v=S.originalQuery,N=(p=S.nextDomain,E=i.domain,U=r(p,i),L=E.indexOf(U),E[(L+1)%E.length]||p);y={nextDomain:N,nextRetryUrl:t(S.nextRetryUrl,S.nextDomain,N,e,v,i),originalScriptFilename:m,originalSrcUrl:g,originalQuery:v}}return o?(a[n][R]=y,l[n]=y):(_[n][R]=y,c[n]=y),y}(e,N,v);p=A.originalScriptFilename,E=A.nextRetryUrl,U=A.nextDomain}catch(r){throw console.error(n,"failed to get nextRetryUrl",r),u}var C=function(n){return{times:n,domain:U,url:E,tagName:v?"link":"script",isAsyncChunk:!0}},T=C(N);if(N>=o)throw u.message=(null==(L=u.message)?void 0:L.includes("retries:"))?u.message:"Loading chunk ".concat(e,' from "').concat(p,'" failed after ').concat(o,' retries: "').concat(u.message,'"'),"function"==typeof i.onFail&&i.onFail(T),u;var I=i.test;if(I){if("string"==typeof I){var w=new RegExp(I);I=function(n){return w.test(n)}}if("function"!=typeof I||!I(E))throw u}if(i.domain&&i.domain.length>0&&-1===i.domain.indexOf(U))throw u;"function"==typeof i.onRetry&&i.onRetry(T);var O="function"==typeof i.delay?i.delay(T):i.delay;return(O>0?new Promise(function(n){return setTimeout(n,O)}):Promise.resolve()).then(function(){return y.apply(y,d)}).then(function(n){var r=(null==S?void 0:S.count)===m+2;if("function"==typeof i.onSuccess&&r){var e=C(N+1);i.onSuccess(e)}return n})})):R}if("undefined"==typeof window||window.__RB_ASYNC_CHUNKS__||(window.__RB_ASYNC_CHUNKS__={}),"undefined"!=typeof __RUNTIME_GLOBALS_REQUIRE__)try{__RUNTIME_GLOBALS_ENSURE_CHUNK__=y,__RUNTIME_GLOBALS_LOAD_SCRIPT__=function(){var n=Array.prototype.slice.call(arguments),r=c[n[3]];return r&&(n[0]=r.nextRetryUrl),d.apply(null,n)},__RUNTIME_GLOBALS_RSBUILD_LOAD_STYLESHEET__=function(n,r){var e=l[r];return e&&e.nextRetryUrl||__RUNTIME_GLOBALS_PUBLIC_PATH__+n}}catch(r){console.error(n,"Register async chunk retry runtime failed",r)}}();
1
+ !function(){"use strict";var n="[@rsbuild/plugin-assets-retry] ";function r(n,r){for(var e=r.domain,t=0;t<e.length;t++){var i=e[t];if(-1!==n.indexOf(i))return i}return window.origin}var e=/[?#].*$/;function t(n,r,t,i,o,_){var a;return n.replace(r,t).replace(e,"")+(a=i+1,!0===_.addQuery?""!==o?"".concat(o,"&retry=").concat(a):"?retry=".concat(a):"function"==typeof _.addQuery?_.addQuery({times:a,originalQuery:o}):"")}var i=__RETRY_OPTIONS__,o={},_={},a={},l={},u=__RUNTIME_GLOBALS_ENSURE_CHUNK__,c=__RUNTIME_GLOBALS_GET_CHUNK_SCRIPT_FILENAME__,s=__RUNTIME_GLOBALS_GET_MINI_CSS_EXTRACT_FILENAME__||__RUNTIME_GLOBALS_GET_CSS_FILENAME__||function(){return null},f=__RUNTIME_GLOBALS_LOAD_SCRIPT__;function y(e){var f=Array.prototype.slice.call(arguments);f[10]||(f[10]={count:0,cssFailedCount:0});var d=f[10],S=u.apply(null,f);try{var p=c(e),R=s(e);"undefined"!=typeof window&&(p&&(window.__RB_ASYNC_CHUNKS__[p]=!0),R&&(window.__RB_ASYNC_CHUNKS__[R]=!0))}catch(r){console.error(n,"get original script or CSS filename error",r)}return d&&"number"==typeof d.count&&"number"==typeof d.cssFailedCount?(d.count+=1,S.catch(function(u){var S,p,R,m,E,U,g=d.count-1,v=d.cssFailedCount,L=!!(null==u||null==(S=u.message)?void 0:S.includes("CSS chunk"));L&&(d.cssFailedCount+=1);var N=L?v:g-v;try{var A=function(n,e,u){var f,y,d,S=u?null==(f=_[n])?void 0:f[e]:null==(y=o[n])?void 0:y[e],p=e+1;if(0===e||void 0===S){if(!(d=function(n,e){var o,_=e?s(n):c(n);if(!_)throw Error("only support cssExtract");var a=__RUNTIME_GLOBALS_PUBLIC_PATH__,l="/"===a[0]&&"/"!==a[1]?window.origin+a+_:a+_,u=(o=l.split("?")[1])?"?".concat(o.split("#")[0]):"",f=function(n,e,t){for(var i=0;i<t.length;i++){var o,_=t[i],a=_.test,l=!0;if((null!=(o=RegExp)&&"undefined"!=typeof Symbol&&o[Symbol.hasInstance]?!!o[Symbol.hasInstance](a):a instanceof o)?l=a.test(n):"string"==typeof a?l=new RegExp(a).test(n):"function"==typeof a&&(l=a(n)),_.domain&&_.domain.length>0){var u=r(n,_);_.domain.includes(u)||(l=!1)}if(_.type&&_.type.length>0&&!_.type.includes(e)&&(l=!1),l)return _}return null}(l,e?"link":"script",i);if(!f)return null;var y=r(l,f);return{nextDomain:y,nextRetryUrl:t(l,y,y,0,u,f),originalScriptFilename:_,originalSrcUrl:l,originalQuery:u,rule:f}}(n,u)))return null;u?_[n]=[]:o[n]=[]}else{var R,m,E,U,g=S.originalScriptFilename,v=S.originalSrcUrl,L=S.originalQuery,N=S.rule,A=(R=S.nextDomain,m=N.domain,E=r(R,N),-1===(U=m.indexOf(E))?E:m[(U+1)%m.length]);d={nextDomain:A,nextRetryUrl:t(S.nextRetryUrl,S.nextDomain,A,e,L,N),originalScriptFilename:g,originalSrcUrl:v,originalQuery:L,rule:N}}return u?(_[n][p]=d,l[n]=d):(o[n][p]=d,a[n]=d),d}(e,N,L);if(!A)throw u;p=A.originalScriptFilename,R=A.nextRetryUrl,m=A.nextDomain,E=A.rule}catch(r){throw r!==u&&console.error(n,"failed to get nextRetryUrl",r),u}var C=function(n){return{times:n,domain:m,url:R,tagName:L?"link":"script",isAsyncChunk:!0}},I=C(N);if(N>=E.max)throw u.message=(null==(U=u.message)?void 0:U.includes("retries:"))?u.message:"Loading chunk ".concat(e,' from "').concat(p,'" failed after ').concat(E.max,' retries: "').concat(u.message,'"'),"function"==typeof E.onFail&&E.onFail(I),u;"function"==typeof E.onRetry&&E.onRetry(I);var T="function"==typeof E.delay?E.delay(I):E.delay;return(T>0?new Promise(function(n){return setTimeout(n,T)}):Promise.resolve()).then(function(){return y.apply(y,f)}).then(function(n){var r=(null==d?void 0:d.count)===g+2;if("function"==typeof E.onSuccess&&r){var e=C(N+1);E.onSuccess(e)}return n})})):S}if("undefined"==typeof window||window.__RB_ASYNC_CHUNKS__||(window.__RB_ASYNC_CHUNKS__={}),"undefined"!=typeof __RUNTIME_GLOBALS_REQUIRE__)try{__RUNTIME_GLOBALS_ENSURE_CHUNK__=y,__RUNTIME_GLOBALS_LOAD_SCRIPT__=function(){var n=Array.prototype.slice.call(arguments),r=a[n[3]];return r&&(n[0]=r.nextRetryUrl),f.apply(null,n)},__RUNTIME_GLOBALS_RSBUILD_LOAD_STYLESHEET__=function(n,r){var e=l[r];return e&&e.nextRetryUrl||__RUNTIME_GLOBALS_PUBLIC_PATH__+n}}catch(r){console.error(n,"Register async chunk retry runtime failed",r)}}();
@@ -3,18 +3,17 @@
3
3
  var ERROR_PREFIX = '[@rsbuild/plugin-assets-retry] ';
4
4
  function findCurrentDomain(url, config) {
5
5
  var domains = config.domain;
6
- var domain = '';
7
- for(var i = 0; i < domains.length; i++)if (-1 !== url.indexOf(domains[i])) {
8
- domain = domains[i];
9
- break;
6
+ for(var i = 0; i < domains.length; i++){
7
+ var domain = domains[i];
8
+ if (-1 !== url.indexOf(domain)) return domain;
10
9
  }
11
- return domain || window.origin;
10
+ return window.origin;
12
11
  }
13
12
  function findNextDomain(url, config) {
14
13
  var domains = config.domain;
15
14
  var currentDomain = findCurrentDomain(url, config);
16
15
  var index = domains.indexOf(currentDomain);
17
- return domains[(index + 1) % domains.length] || url;
16
+ return -1 === index ? currentDomain : domains[(index + 1) % domains.length];
18
17
  }
19
18
  var postfixRE = /[?#].*$/;
20
19
  function cleanUrl(url) {
@@ -39,26 +38,58 @@
39
38
  if (null != right && "undefined" != typeof Symbol && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);
40
39
  return left instanceof right;
41
40
  }
41
+ function findMatchingRule(url, type, rules) {
42
+ for(var i = 0; i < rules.length; i++){
43
+ var rule = rules[i];
44
+ var tester = rule.test;
45
+ var shouldMatch = true;
46
+ if (_instanceof(tester, RegExp)) shouldMatch = tester.test(url);
47
+ else if ('string' == typeof tester) {
48
+ var regexp = new RegExp(tester);
49
+ shouldMatch = regexp.test(url);
50
+ } else if ('function' == typeof tester) shouldMatch = tester(url);
51
+ if (rule.domain && rule.domain.length > 0) {
52
+ var domain = findCurrentDomain(url, rule);
53
+ if (!rule.domain.includes(domain)) shouldMatch = false;
54
+ }
55
+ if (rule.type && rule.type.length > 0) {
56
+ if (!rule.type.includes(type)) shouldMatch = false;
57
+ }
58
+ if (shouldMatch) return rule;
59
+ }
60
+ return null;
61
+ }
62
+ function initialChunkRetry_instanceof(left, right) {
63
+ if (null != right && "undefined" != typeof Symbol && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);
64
+ return left instanceof right;
65
+ }
42
66
  var TAG_TYPE = {
43
67
  link: HTMLLinkElement,
44
68
  script: HTMLScriptElement,
45
69
  img: HTMLImageElement
46
70
  };
47
71
  function getRequestUrl(element) {
48
- if (_instanceof(element, HTMLScriptElement) || _instanceof(element, HTMLImageElement)) return element.src;
49
- if (_instanceof(element, HTMLLinkElement)) return element.href;
72
+ if (initialChunkRetry_instanceof(element, HTMLScriptElement) || initialChunkRetry_instanceof(element, HTMLImageElement)) return element.src;
73
+ if (initialChunkRetry_instanceof(element, HTMLLinkElement)) return element.href;
50
74
  return null;
51
75
  }
52
- function validateTargetInfo(config, e) {
76
+ function validateTargetInfo(rules, e) {
53
77
  var target = e.target;
54
78
  var tagName = target.tagName.toLocaleLowerCase();
55
- var allowTags = config.type;
56
79
  var url = getRequestUrl(target);
57
- if (!tagName || -1 === allowTags.indexOf(tagName) || !TAG_TYPE[tagName] || !_instanceof(target, TAG_TYPE[tagName]) || !url) return false;
80
+ if (!url) return false;
81
+ var ruleIndex = Number(target.dataset.rbRuleI || '-1');
82
+ var rule = rules[ruleIndex] || findMatchingRule(url, tagName, rules);
83
+ if (!rule) return false;
84
+ ruleIndex = rules.indexOf(rule);
85
+ var allowTags = rule.type;
86
+ if (!tagName || -1 === allowTags.indexOf(tagName) || !TAG_TYPE[tagName] || !initialChunkRetry_instanceof(target, TAG_TYPE[tagName])) return false;
58
87
  return {
59
88
  target: target,
60
89
  tagName: tagName,
61
- url: url
90
+ url: url,
91
+ rule: rule,
92
+ ruleIndex: ruleIndex
62
93
  };
63
94
  }
64
95
  function createElement(origin, attributes) {
@@ -66,20 +97,22 @@
66
97
  var crossOriginAttr = crossOrigin ? 'crossorigin="'.concat(crossOrigin, '"') : '';
67
98
  var retryTimesAttr = attributes.times ? 'data-rb-retry-times="'.concat(attributes.times, '"') : '';
68
99
  var originalQueryAttr = attributes.originalQuery ? 'data-rb-original-query="'.concat(attributes.originalQuery, '"') : '';
100
+ var ruleIndexAttr = attributes.ruleIndex >= 0 ? 'data-rb-rule-i="'.concat(attributes.ruleIndex, '"') : '';
69
101
  var isAsyncAttr = attributes.isAsync ? 'data-rb-async' : '';
70
- if (_instanceof(origin, HTMLScriptElement)) {
102
+ if (initialChunkRetry_instanceof(origin, HTMLScriptElement)) {
71
103
  var script = document.createElement("script");
72
104
  script.src = attributes.url;
73
105
  if (crossOrigin) script.crossOrigin = crossOrigin;
74
106
  if (attributes.times) script.dataset.rbRetryTimes = String(attributes.times);
75
107
  if (attributes.isAsync) script.dataset.rbAsync = '';
76
108
  if (void 0 !== attributes.originalQuery) script.dataset.rbOriginalQuery = attributes.originalQuery;
109
+ if (attributes.ruleIndex >= 0) script.dataset.rbRuleI = String(attributes.ruleIndex);
77
110
  return {
78
111
  element: script,
79
- str: '<script src="'.concat(attributes.url, '" ').concat(crossOriginAttr, " ").concat(retryTimesAttr, " ").concat(isAsyncAttr, " ").concat(originalQueryAttr, ">") + "<\/script>"
112
+ str: '<script src="'.concat(attributes.url, '" ').concat(crossOriginAttr, " ").concat(retryTimesAttr, " ").concat(isAsyncAttr, " ").concat(ruleIndexAttr, " ").concat(originalQueryAttr, ">") + "<\/script>"
80
113
  };
81
114
  }
82
- if (_instanceof(origin, HTMLLinkElement)) {
115
+ if (initialChunkRetry_instanceof(origin, HTMLLinkElement)) {
83
116
  var link = document.createElement('link');
84
117
  link.rel = origin.rel || 'stylesheet';
85
118
  if (origin.as) link.as = origin.as;
@@ -89,42 +122,31 @@
89
122
  if (void 0 !== attributes.originalQuery) link.dataset.rbOriginalQuery = attributes.originalQuery;
90
123
  return {
91
124
  element: link,
92
- str: '<link rel="'.concat(link.rel, '" href="').concat(attributes.url, '" ').concat(crossOriginAttr, " ").concat(retryTimesAttr, " ").concat(link.as ? 'as="'.concat(link.as, '"') : '', " ").concat(originalQueryAttr, "></link>")
125
+ str: '<link rel="'.concat(link.rel, '" href="').concat(attributes.url, '" ').concat(crossOriginAttr, " ").concat(retryTimesAttr, " ").concat(link.as ? 'as="'.concat(link.as, '"') : '', " ").concat(ruleIndexAttr, " ").concat(originalQueryAttr, "></link>")
93
126
  };
94
127
  }
95
128
  }
96
129
  function reloadElementResource(origin, fresh, attributes) {
97
- if (_instanceof(origin, HTMLScriptElement)) if (attributes.isAsync) document.body.appendChild(fresh.element);
130
+ if (initialChunkRetry_instanceof(origin, HTMLScriptElement)) if (attributes.isAsync) document.body.appendChild(fresh.element);
98
131
  else console.warn(ERROR_PREFIX, "load sync script failed, for security only async/defer script can be retried", origin);
99
- if (_instanceof(origin, HTMLLinkElement)) document.getElementsByTagName('head')[0].appendChild(fresh.element);
100
- if (_instanceof(origin, HTMLImageElement)) {
132
+ if (initialChunkRetry_instanceof(origin, HTMLLinkElement)) document.getElementsByTagName('head')[0].appendChild(fresh.element);
133
+ if (initialChunkRetry_instanceof(origin, HTMLImageElement)) {
101
134
  origin.src = attributes.url;
102
135
  origin.dataset.rbRetryTimes = String(attributes.times);
103
136
  origin.dataset.rbOriginalQuery = String(attributes.originalQuery);
104
137
  }
105
138
  }
106
- function retry(config, e) {
107
- var targetInfo = validateTargetInfo(config, e);
139
+ function retry(rules, e) {
140
+ var targetInfo = validateTargetInfo(rules, e);
108
141
  if (false === targetInfo) return;
109
- var target = targetInfo.target, tagName = targetInfo.tagName, url = targetInfo.url;
142
+ var target = targetInfo.target, tagName = targetInfo.tagName, url = targetInfo.url, rule = targetInfo.rule, ruleIndex = targetInfo.ruleIndex;
110
143
  if ('undefined' != typeof window && Object.keys(window.__RB_ASYNC_CHUNKS__ || {}).some(function(chunkName) {
111
144
  return -1 !== url.indexOf(chunkName);
112
145
  })) return;
113
- var tester = config.test;
114
- if (tester) {
115
- if ('string' == typeof tester) {
116
- var regexp = new RegExp(tester);
117
- tester = function(str) {
118
- return regexp.test(str);
119
- };
120
- }
121
- if ('function' != typeof tester || !tester(url)) return;
122
- }
123
- var domain = findCurrentDomain(url, config);
124
- if (config.domain && config.domain.length > 0 && -1 === config.domain.indexOf(domain)) return;
146
+ var domain = findCurrentDomain(url, rule);
125
147
  var existRetryTimes = Number(target.dataset.rbRetryTimes) || 0;
126
- if (existRetryTimes === config.max) {
127
- if ('function' == typeof config.onFail) {
148
+ if (existRetryTimes === rule.max) {
149
+ if ('function' == typeof rule.onFail) {
128
150
  var context = {
129
151
  times: existRetryTimes,
130
152
  domain: domain,
@@ -132,20 +154,21 @@
132
154
  tagName: tagName,
133
155
  isAsyncChunk: false
134
156
  };
135
- config.onFail(context);
157
+ rule.onFail(context);
136
158
  }
137
159
  return;
138
160
  }
139
- var nextDomain = findNextDomain(domain, config);
161
+ var nextDomain = findNextDomain(domain, rule);
140
162
  var _target_dataset_rbOriginalQuery;
141
163
  var originalQuery = null != (_target_dataset_rbOriginalQuery = target.dataset.rbOriginalQuery) ? _target_dataset_rbOriginalQuery : getQueryFromUrl(url);
142
164
  var isAsync = Boolean(target.dataset.rbAsync) || target.async || target.defer;
143
165
  var attributes = {
144
- url: getNextRetryUrl(url, domain, nextDomain, existRetryTimes, originalQuery, config),
166
+ url: getNextRetryUrl(url, domain, nextDomain, existRetryTimes, originalQuery, rule),
145
167
  times: existRetryTimes + 1,
146
- crossOrigin: config.crossOrigin,
147
- isAsync: isAsync,
148
- originalQuery: originalQuery
168
+ originalQuery: originalQuery,
169
+ ruleIndex: ruleIndex,
170
+ crossOrigin: rule.crossOrigin,
171
+ isAsync: isAsync
149
172
  };
150
173
  var element = createElement(target, attributes);
151
174
  var context1 = {
@@ -155,21 +178,21 @@
155
178
  tagName: tagName,
156
179
  isAsyncChunk: false
157
180
  };
158
- if ('function' == typeof config.onRetry) config.onRetry(context1);
159
- var delayValue = 'function' == typeof config.delay ? config.delay(context1) : config.delay;
181
+ if ('function' == typeof rule.onRetry) rule.onRetry(context1);
182
+ var delayValue = 'function' == typeof rule.delay ? rule.delay(context1) : rule.delay;
160
183
  if (delayValue > 0) setTimeout(function() {
161
184
  reloadElementResource(target, element, attributes);
162
185
  }, delayValue);
163
186
  else reloadElementResource(target, element, attributes);
164
187
  }
165
- function load(config, e) {
166
- var targetInfo = validateTargetInfo(config, e);
188
+ function load(rules, e) {
189
+ var targetInfo = validateTargetInfo(rules, e);
167
190
  if (false === targetInfo) return;
168
- var target = targetInfo.target, tagName = targetInfo.tagName, url = targetInfo.url;
169
- var domain = findCurrentDomain(url, config);
191
+ var target = targetInfo.target, tagName = targetInfo.tagName, url = targetInfo.url, rule = targetInfo.rule;
192
+ var domain = findCurrentDomain(url, rule);
170
193
  var retryTimes = Number(target.dataset.rbRetryTimes) || 0;
171
194
  if (0 === retryTimes) return;
172
- if ('function' == typeof config.onSuccess) {
195
+ if ('function' == typeof rule.onSuccess) {
173
196
  var context = {
174
197
  times: retryTimes,
175
198
  domain: domain,
@@ -177,7 +200,7 @@
177
200
  tagName: tagName,
178
201
  isAsyncChunk: false
179
202
  };
180
- config.onSuccess(context);
203
+ rule.onSuccess(context);
181
204
  }
182
205
  }
183
206
  function registerInitialChunkRetry() {
@@ -186,14 +209,14 @@
186
209
  var config = __RETRY_OPTIONS__;
187
210
  if ('undefined' != typeof window && void 0 !== window.document) {
188
211
  document.addEventListener('error', function(e) {
189
- if (e && _instanceof(e.target, Element)) try {
212
+ if (e && initialChunkRetry_instanceof(e.target, Element)) try {
190
213
  retry(config, e);
191
214
  } catch (err) {
192
215
  console.error('retry error captured', err);
193
216
  }
194
217
  }, true);
195
218
  document.addEventListener('load', function(e) {
196
- if (e && _instanceof(e.target, Element)) try {
219
+ if (e && initialChunkRetry_instanceof(e.target, Element)) try {
197
220
  load(config, e);
198
221
  } catch (err) {
199
222
  console.error('load error captured', err);
@@ -1 +1 @@
1
- !function(){"use strict";function e(e,t){for(var n=t.domain,r="",i=0;i<n.length;i++)if(-1!==e.indexOf(n[i])){r=n[i];break}return r||window.origin}var t=/[?#].*$/;function n(e,t){return null!=t&&"undefined"!=typeof Symbol&&t[Symbol.hasInstance]?!!t[Symbol.hasInstance](e):e instanceof t}var r={link:HTMLLinkElement,script:HTMLScriptElement,img:HTMLImageElement};function i(e,t){var i=t.target,a=i.tagName.toLocaleLowerCase(),o=e.type,c=n(i,HTMLScriptElement)||n(i,HTMLImageElement)?i.src:n(i,HTMLLinkElement)?i.href:null;return!!a&&-1!==o.indexOf(a)&&!!r[a]&&!!n(i,r[a])&&!!c&&{target:i,tagName:a,url:c}}function a(e,t,r){n(e,HTMLScriptElement)&&(r.isAsync?document.body.appendChild(t.element):console.warn("[@rsbuild/plugin-assets-retry] ","load sync script failed, for security only async/defer script can be retried",e)),n(e,HTMLLinkElement)&&document.getElementsByTagName("head")[0].appendChild(t.element),n(e,HTMLImageElement)&&(e.src=r.url,e.dataset.rbRetryTimes=String(r.times),e.dataset.rbOriginalQuery=String(r.originalQuery))}"undefined"==typeof window||window.__RB_ASYNC_CHUNKS__||(window.__RB_ASYNC_CHUNKS__={});try{var o=__RETRY_OPTIONS__;"undefined"!=typeof window&&void 0!==window.document&&(document.addEventListener("error",function(r){if(r&&n(r.target,Element))try{!function(r,o){var c,s=i(r,o);if(!1!==s){var l=s.target,u=s.tagName,d=s.url;if(!("undefined"!=typeof window&&Object.keys(window.__RB_ASYNC_CHUNKS__||{}).some(function(e){return -1!==d.indexOf(e)}))){var m=r.test;if(m){if("string"==typeof m){var y=new RegExp(m);m=function(e){return y.test(e)}}if("function"!=typeof m||!m(d))return}var f=e(d,r);if(!r.domain||!(r.domain.length>0)||-1!==r.domain.indexOf(f)){var g,p,b,v,_=Number(l.dataset.rbRetryTimes)||0;if(_===r.max){"function"==typeof r.onFail&&r.onFail({times:_,domain:f,url:d,tagName:u,isAsyncChunk:!1});return}var E=(g=r.domain,p=e(f,r),b=g.indexOf(p),g[(b+1)%g.length]||f),S=null!=(c=l.dataset.rbOriginalQuery)?c:(v=d.split("?")[1])?"?".concat(v.split("#")[0]):"",T=!!l.dataset.rbAsync||l.async||l.defer,w={url:function(e,n,r,i,a,o){var c;return e.replace(n,r).replace(t,"")+(c=i+1,!0===o.addQuery?""!==a?"".concat(a,"&retry=").concat(c):"?retry=".concat(c):"function"==typeof o.addQuery?o.addQuery({times:c,originalQuery:a}):"")}(d,f,E,_,S,r),times:_+1,crossOrigin:r.crossOrigin,isAsync:T,originalQuery:S},L=function(e,t){var r=!0===t.crossOrigin?"anonymous":t.crossOrigin,i=r?'crossorigin="'.concat(r,'"'):"",a=t.times?'data-rb-retry-times="'.concat(t.times,'"'):"",o=t.originalQuery?'data-rb-original-query="'.concat(t.originalQuery,'"'):"",c=t.isAsync?"data-rb-async":"";if(n(e,HTMLScriptElement)){var s=document.createElement("script");return s.src=t.url,r&&(s.crossOrigin=r),t.times&&(s.dataset.rbRetryTimes=String(t.times)),t.isAsync&&(s.dataset.rbAsync=""),void 0!==t.originalQuery&&(s.dataset.rbOriginalQuery=t.originalQuery),{element:s,str:'<script src="'.concat(t.url,'" ').concat(i," ").concat(a," ").concat(c," ").concat(o,">")+"<\/script>"}}if(n(e,HTMLLinkElement)){var l=document.createElement("link");return l.rel=e.rel||"stylesheet",e.as&&(l.as=e.as),l.href=t.url,r&&(l.crossOrigin=r),t.times&&(l.dataset.rbRetryTimes=String(t.times)),void 0!==t.originalQuery&&(l.dataset.rbOriginalQuery=t.originalQuery),{element:l,str:'<link rel="'.concat(l.rel,'" href="').concat(t.url,'" ').concat(i," ").concat(a," ").concat(l.as?'as="'.concat(l.as,'"'):""," ").concat(o,"></link>")}}}(l,w),h={times:_,domain:f,url:d,tagName:u,isAsyncChunk:!1};"function"==typeof r.onRetry&&r.onRetry(h);var O="function"==typeof r.delay?r.delay(h):r.delay;O>0?setTimeout(function(){a(l,L,w)},O):a(l,L,w)}}}}(o,r)}catch(e){console.error("retry error captured",e)}},!0),document.addEventListener("load",function(t){if(t&&n(t.target,Element))try{!function(t,n){var r=i(t,n);if(!1!==r){var a=r.target,o=r.tagName,c=r.url,s=e(c,t),l=Number(a.dataset.rbRetryTimes)||0;0!==l&&"function"==typeof t.onSuccess&&t.onSuccess({times:l,domain:s,url:c,tagName:o,isAsyncChunk:!1})}}(o,t)}catch(e){console.error("load error captured",e)}},!0))}catch(e){console.error("monitor error captured",e)}}();
1
+ !function(){"use strict";function e(e,n){for(var t=n.domain,r=0;r<t.length;r++){var a=t[r];if(-1!==e.indexOf(a))return a}return window.origin}var n=/[?#].*$/;function t(e,n){return null!=n&&"undefined"!=typeof Symbol&&n[Symbol.hasInstance]?!!n[Symbol.hasInstance](e):e instanceof n}var r={link:HTMLLinkElement,script:HTMLScriptElement,img:HTMLImageElement};function a(n,a){var i=a.target,o=i.tagName.toLocaleLowerCase(),c=t(i,HTMLScriptElement)||t(i,HTMLImageElement)?i.src:t(i,HTMLLinkElement)?i.href:null;if(!c)return!1;var s=Number(i.dataset.rbRuleI||"-1"),l=n[s]||function(n,t,r){for(var a=0;a<r.length;a++){var i,o=r[a],c=o.test,s=!0;if((null!=(i=RegExp)&&"undefined"!=typeof Symbol&&i[Symbol.hasInstance]?!!i[Symbol.hasInstance](c):c instanceof i)?s=c.test(n):"string"==typeof c?s=new RegExp(c).test(n):"function"==typeof c&&(s=c(n)),o.domain&&o.domain.length>0){var l=e(n,o);o.domain.includes(l)||(s=!1)}if(o.type&&o.type.length>0&&!o.type.includes(t)&&(s=!1),s)return o}return null}(c,o,n);if(!l)return!1;s=n.indexOf(l);var u=l.type;return!!o&&-1!==u.indexOf(o)&&!!r[o]&&!!t(i,r[o])&&{target:i,tagName:o,url:c,rule:l,ruleIndex:s}}function i(e,n,r){t(e,HTMLScriptElement)&&(r.isAsync?document.body.appendChild(n.element):console.warn("[@rsbuild/plugin-assets-retry] ","load sync script failed, for security only async/defer script can be retried",e)),t(e,HTMLLinkElement)&&document.getElementsByTagName("head")[0].appendChild(n.element),t(e,HTMLImageElement)&&(e.src=r.url,e.dataset.rbRetryTimes=r.times+"",e.dataset.rbOriginalQuery=r.originalQuery+"")}"undefined"==typeof window||window.__RB_ASYNC_CHUNKS__||(window.__RB_ASYNC_CHUNKS__={});try{var o=__RETRY_OPTIONS__;"undefined"!=typeof window&&void 0!==window.document&&(document.addEventListener("error",function(r){if(r&&t(r.target,Element))try{!function(r,o){var c,s=a(r,o);if(!1!==s){var l=s.target,u=s.tagName,d=s.url,m=s.rule,y=s.ruleIndex;if(!("undefined"!=typeof window&&Object.keys(window.__RB_ASYNC_CHUNKS__||{}).some(function(e){return -1!==d.indexOf(e)}))){var f,g,p,b,v,_=e(d,m),h=Number(l.dataset.rbRetryTimes)||0;if(h===m.max){"function"==typeof m.onFail&&m.onFail({times:h,domain:_,url:d,tagName:u,isAsyncChunk:!1});return}var E=(g=m.domain,p=e(_,m),-1===(b=g.indexOf(p))?p:g[(b+1)%g.length]),T=null!=(c=l.dataset.rbOriginalQuery)?c:(v=d.split("?")[1])?"?".concat(v.split("#")[0]):"",w=!!l.dataset.rbAsync||l.async||l.defer,L={url:d.replace(_,E).replace(n,"")+(f=h+1,!0===m.addQuery?""!==T?"".concat(T,"&retry=").concat(f):"?retry=".concat(f):"function"==typeof m.addQuery?m.addQuery({times:f,originalQuery:T}):""),times:h+1,originalQuery:T,ruleIndex:y,crossOrigin:m.crossOrigin,isAsync:w},S=function(e,n){var r=!0===n.crossOrigin?"anonymous":n.crossOrigin,a=r?'crossorigin="'.concat(r,'"'):"",i=n.times?'data-rb-retry-times="'.concat(n.times,'"'):"",o=n.originalQuery?'data-rb-original-query="'.concat(n.originalQuery,'"'):"",c=n.ruleIndex>=0?'data-rb-rule-i="'.concat(n.ruleIndex,'"'):"",s=n.isAsync?"data-rb-async":"";if(t(e,HTMLScriptElement)){var l=document.createElement("script");return l.src=n.url,r&&(l.crossOrigin=r),n.times&&(l.dataset.rbRetryTimes=n.times+""),n.isAsync&&(l.dataset.rbAsync=""),void 0!==n.originalQuery&&(l.dataset.rbOriginalQuery=n.originalQuery),n.ruleIndex>=0&&(l.dataset.rbRuleI=n.ruleIndex+""),{element:l,str:'<script src="'.concat(n.url,'" ').concat(a," ").concat(i," ").concat(s," ").concat(c," ").concat(o,">")+"<\/script>"}}if(t(e,HTMLLinkElement)){var u=document.createElement("link");return u.rel=e.rel||"stylesheet",e.as&&(u.as=e.as),u.href=n.url,r&&(u.crossOrigin=r),n.times&&(u.dataset.rbRetryTimes=n.times+""),void 0!==n.originalQuery&&(u.dataset.rbOriginalQuery=n.originalQuery),{element:u,str:'<link rel="'.concat(u.rel,'" href="').concat(n.url,'" ').concat(a," ").concat(i," ").concat(u.as?'as="'.concat(u.as,'"'):""," ").concat(c," ").concat(o,"></link>")}}}(l,L),N={times:h,domain:_,url:d,tagName:u,isAsyncChunk:!1};"function"==typeof m.onRetry&&m.onRetry(N);var O="function"==typeof m.delay?m.delay(N):m.delay;O>0?setTimeout(function(){i(l,S,L)},O):i(l,S,L)}}}(o,r)}catch(e){console.error("retry error captured",e)}},!0),document.addEventListener("load",function(n){if(n&&t(n.target,Element))try{!function(n,t){var r=a(n,t);if(!1!==r){var i=r.target,o=r.tagName,c=r.url,s=r.rule,l=e(c,s),u=Number(i.dataset.rbRetryTimes)||0;0!==u&&"function"==typeof s.onSuccess&&s.onSuccess({times:u,domain:l,url:c,tagName:o,isAsyncChunk:!1})}}(o,n)}catch(e){console.error("load error captured",e)}},!0))}catch(e){console.error("monitor error captured",e)}}();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsbuild/plugin-assets-retry",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "repository": "https://github.com/rspack-contrib/rsbuild-plugin-assets-retry",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,16 +30,16 @@
30
30
  "devDependencies": {
31
31
  "@microsoft/api-extractor": "^7.52.8",
32
32
  "@biomejs/biome": "^1.9.4",
33
- "@playwright/test": "^1.53.0",
34
- "@rsbuild/core": "^1.3.22",
33
+ "@playwright/test": "^1.53.2",
34
+ "@rsbuild/core": "^1.4.2",
35
35
  "@rsbuild/plugin-react": "^1.3.2",
36
- "@rslib/core": "^0.10.0",
37
- "@swc/core": "^1.12.1",
38
- "@types/node": "^22.15.32",
36
+ "@rslib/core": "^0.10.4",
37
+ "@swc/core": "^1.12.7",
38
+ "@types/node": "^22.15.34",
39
39
  "@types/react": "^19.1.8",
40
40
  "@types/react-dom": "^19.1.6",
41
41
  "@types/serialize-javascript": "^5.0.4",
42
- "playwright": "^1.53.0",
42
+ "playwright": "^1.53.2",
43
43
  "react": "^19.1.0",
44
44
  "react-dom": "^19.1.0",
45
45
  "serialize-javascript": "^6.0.2",
@@ -54,7 +54,7 @@
54
54
  "optional": true
55
55
  }
56
56
  },
57
- "packageManager": "pnpm@10.12.2",
57
+ "packageManager": "pnpm@10.12.4",
58
58
  "publishConfig": {
59
59
  "access": "public",
60
60
  "registry": "https://registry.npmjs.org/"