@rsbuild/plugin-assets-retry 1.2.2 → 1.3.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 +18 -14
- package/README.zh-CN.md +18 -14
- package/dist/index.cjs +27 -36
- package/dist/index.d.ts +96 -5
- package/dist/index.js +27 -36
- package/dist/runtime/asyncChunkRetry.js +165 -219
- package/dist/runtime/asyncChunkRetry.min.js +1 -1
- package/dist/runtime/initialChunkRetry.js +181 -264
- package/dist/runtime/initialChunkRetry.min.js +1 -1
- package/package.json +3 -2
- package/dist/AsyncChunkRetryPlugin.d.ts +0 -15
- package/dist/runtime/asyncChunkRetry.d.ts +0 -19
- package/dist/runtime/initialChunkRetry.d.ts +0 -5
- package/dist/types.d.ts +0 -72
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ bun add @rsbuild/plugin-assets-retry -D
|
|
|
37
37
|
You can register the plugin in the `rsbuild.config.ts` file:
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
|
-
import { pluginAssetsRetry } from
|
|
40
|
+
import { pluginAssetsRetry } from '@rsbuild/plugin-assets-retry';
|
|
41
41
|
|
|
42
42
|
export default {
|
|
43
43
|
plugins: [pluginAssetsRetry()],
|
|
@@ -64,7 +64,7 @@ type AssetsRetryOptions = {
|
|
|
64
64
|
domain?: string[];
|
|
65
65
|
max?: number;
|
|
66
66
|
test?: string | ((url: string) => boolean);
|
|
67
|
-
crossOrigin?: boolean |
|
|
67
|
+
crossOrigin?: boolean | 'anonymous' | 'use-credentials';
|
|
68
68
|
inlineScript?: boolean;
|
|
69
69
|
delay?: number | ((context: AssetsRetryHookContext) => number);
|
|
70
70
|
onRetry?: (context: AssetsRetryHookContext) => void;
|
|
@@ -77,10 +77,10 @@ type AssetsRetryOptions = {
|
|
|
77
77
|
|
|
78
78
|
```ts
|
|
79
79
|
const defaultAssetsRetryOptions = {
|
|
80
|
-
type: [
|
|
80
|
+
type: ['script', 'link', 'img'],
|
|
81
81
|
domain: [],
|
|
82
82
|
max: 3,
|
|
83
|
-
test:
|
|
83
|
+
test: '',
|
|
84
84
|
crossOrigin: false,
|
|
85
85
|
delay: 0,
|
|
86
86
|
onRetry: () => {},
|
|
@@ -103,11 +103,11 @@ For example:
|
|
|
103
103
|
defineConfig({
|
|
104
104
|
plugins: [
|
|
105
105
|
pluginAssetsRetry({
|
|
106
|
-
domain: [
|
|
107
|
-
})
|
|
106
|
+
domain: ['cdn1.com', 'cdn2.com', 'cdn3.com'],
|
|
107
|
+
}),
|
|
108
108
|
],
|
|
109
109
|
output: {
|
|
110
|
-
assetPrefix:
|
|
110
|
+
assetPrefix: 'https://cdn1.com', // or "//cdn1.com"
|
|
111
111
|
},
|
|
112
112
|
});
|
|
113
113
|
```
|
|
@@ -127,7 +127,7 @@ For example, only script tags and link tags are processed:
|
|
|
127
127
|
|
|
128
128
|
```js
|
|
129
129
|
pluginAssetsRetry({
|
|
130
|
-
type: [
|
|
130
|
+
type: ['script', 'link'],
|
|
131
131
|
});
|
|
132
132
|
```
|
|
133
133
|
|
|
@@ -182,7 +182,7 @@ The callback function when the asset is being retried. For example:
|
|
|
182
182
|
pluginAssetsRetry({
|
|
183
183
|
onRetry: ({ times, domain, url, tagName, isAsyncChunk }) => {
|
|
184
184
|
console.log(
|
|
185
|
-
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}
|
|
185
|
+
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
|
|
186
186
|
);
|
|
187
187
|
},
|
|
188
188
|
});
|
|
@@ -198,7 +198,7 @@ The callback function when the asset is successfully retried. For example:
|
|
|
198
198
|
pluginAssetsRetry({
|
|
199
199
|
onSuccess: ({ times, domain, url, tagName, isAsyncChunk }) => {
|
|
200
200
|
console.log(
|
|
201
|
-
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}
|
|
201
|
+
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
|
|
202
202
|
);
|
|
203
203
|
},
|
|
204
204
|
});
|
|
@@ -214,7 +214,7 @@ The callback function when the asset is failed to be retried. For example:
|
|
|
214
214
|
pluginAssetsRetry({
|
|
215
215
|
onFail: ({ times, domain, url, tagName, isAsyncChunk }) => {
|
|
216
216
|
console.log(
|
|
217
|
-
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}
|
|
217
|
+
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
|
|
218
218
|
);
|
|
219
219
|
},
|
|
220
220
|
});
|
|
@@ -321,7 +321,7 @@ Or pass a function that receives `AssetsRetryHookContext` and returns the delay
|
|
|
321
321
|
```js
|
|
322
322
|
// Calculate delay based on retry attempts
|
|
323
323
|
pluginAssetsRetry({
|
|
324
|
-
delay:
|
|
324
|
+
delay: ctx => (ctx.times + 1) * 1000,
|
|
325
325
|
});
|
|
326
326
|
```
|
|
327
327
|
|
|
@@ -336,12 +336,12 @@ When you use Assets Retry plugin, the Rsbuild injects some runtime code into the
|
|
|
336
336
|
Here's an example of incorrect usage:
|
|
337
337
|
|
|
338
338
|
```js
|
|
339
|
-
import { someMethod } from
|
|
339
|
+
import { someMethod } from 'utils';
|
|
340
340
|
|
|
341
341
|
pluginAssetsRetry({
|
|
342
342
|
onRetry() {
|
|
343
343
|
// Incorrect usage, includes sensitive information
|
|
344
|
-
const privateToken =
|
|
344
|
+
const privateToken = 'a-private-token';
|
|
345
345
|
|
|
346
346
|
// Incorrect usage, uses an external method
|
|
347
347
|
someMethod(privateToken);
|
|
@@ -353,6 +353,10 @@ pluginAssetsRetry({
|
|
|
353
353
|
|
|
354
354
|
Assets Retry plugin may not work in the following scenarios:
|
|
355
355
|
|
|
356
|
+
### Sync script tag loaded resources
|
|
357
|
+
|
|
358
|
+
`<script src="..."></script>` tags load resources synchronously, and retrying them does not guarantee the order of resource loading. Therefore, the Assets Retry plugin will not retry resources loaded by synchronous script tags. It will only retry resources loaded by async/defer script tags.
|
|
359
|
+
|
|
356
360
|
### Module Federation
|
|
357
361
|
|
|
358
362
|
For remote modules loaded by Module Federation, you can use the [@module-federation/retry-plugin](https://www.npmjs.com/package/@module-federation/retry-plugin) from Module Federation 2.0 to implement static asset retries.
|
package/README.zh-CN.md
CHANGED
|
@@ -35,7 +35,7 @@ bun add @rsbuild/plugin-assets-retry -D
|
|
|
35
35
|
你可以在 `rsbuild.config.ts` 文件中注册插件:
|
|
36
36
|
|
|
37
37
|
```ts
|
|
38
|
-
import { pluginAssetsRetry } from
|
|
38
|
+
import { pluginAssetsRetry } from '@rsbuild/plugin-assets-retry';
|
|
39
39
|
|
|
40
40
|
export default {
|
|
41
41
|
plugins: [pluginAssetsRetry()],
|
|
@@ -62,7 +62,7 @@ type AssetsRetryOptions = {
|
|
|
62
62
|
domain?: string[];
|
|
63
63
|
max?: number;
|
|
64
64
|
test?: string | ((url: string) => boolean);
|
|
65
|
-
crossOrigin?: boolean |
|
|
65
|
+
crossOrigin?: boolean | 'anonymous' | 'use-credentials';
|
|
66
66
|
inlineScript?: boolean;
|
|
67
67
|
delay?: number | ((context: AssetsRetryHookContext) => number);
|
|
68
68
|
onRetry?: (context: AssetsRetryHookContext) => void;
|
|
@@ -75,10 +75,10 @@ type AssetsRetryOptions = {
|
|
|
75
75
|
|
|
76
76
|
```ts
|
|
77
77
|
const defaultOptions = {
|
|
78
|
-
type: [
|
|
78
|
+
type: ['script', 'link', 'img'],
|
|
79
79
|
domain: [],
|
|
80
80
|
max: 3,
|
|
81
|
-
test:
|
|
81
|
+
test: '',
|
|
82
82
|
crossOrigin: false,
|
|
83
83
|
delay: 0,
|
|
84
84
|
onRetry: () => {},
|
|
@@ -101,11 +101,11 @@ const defaultOptions = {
|
|
|
101
101
|
defineConfig({
|
|
102
102
|
plugins: [
|
|
103
103
|
pluginAssetsRetry({
|
|
104
|
-
domain: [
|
|
105
|
-
})
|
|
104
|
+
domain: ['cdn1.com', 'cdn2.com', 'cdn3.com'],
|
|
105
|
+
}),
|
|
106
106
|
],
|
|
107
107
|
output: {
|
|
108
|
-
assetPrefix:
|
|
108
|
+
assetPrefix: 'https://cdn1.com', // 或者 "//cdn1.com"
|
|
109
109
|
},
|
|
110
110
|
});
|
|
111
111
|
```
|
|
@@ -125,7 +125,7 @@ defineConfig({
|
|
|
125
125
|
|
|
126
126
|
```js
|
|
127
127
|
pluginAssetsRetry({
|
|
128
|
-
type: [
|
|
128
|
+
type: ['script', 'link'],
|
|
129
129
|
});
|
|
130
130
|
```
|
|
131
131
|
|
|
@@ -180,7 +180,7 @@ pluginAssetsRetry({
|
|
|
180
180
|
pluginAssetsRetry({
|
|
181
181
|
onRetry: ({ times, domain, url, tagName, isAsyncChunk }) => {
|
|
182
182
|
console.log(
|
|
183
|
-
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}
|
|
183
|
+
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
|
|
184
184
|
);
|
|
185
185
|
},
|
|
186
186
|
});
|
|
@@ -196,7 +196,7 @@ pluginAssetsRetry({
|
|
|
196
196
|
pluginAssetsRetry({
|
|
197
197
|
onSuccess: ({ times, domain, url, tagName, isAsyncChunk }) => {
|
|
198
198
|
console.log(
|
|
199
|
-
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}
|
|
199
|
+
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
|
|
200
200
|
);
|
|
201
201
|
},
|
|
202
202
|
});
|
|
@@ -212,7 +212,7 @@ pluginAssetsRetry({
|
|
|
212
212
|
pluginAssetsRetry({
|
|
213
213
|
onFail: ({ times, domain, url, tagName, isAsyncChunk }) => {
|
|
214
214
|
console.log(
|
|
215
|
-
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}
|
|
215
|
+
`Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`,
|
|
216
216
|
);
|
|
217
217
|
},
|
|
218
218
|
});
|
|
@@ -319,7 +319,7 @@ pluginAssetsRetry({
|
|
|
319
319
|
```js
|
|
320
320
|
// 通过次数来计算延迟时间
|
|
321
321
|
pluginAssetsRetry({
|
|
322
|
-
delay:
|
|
322
|
+
delay: ctx => (ctx.times + 1) * 1000,
|
|
323
323
|
});
|
|
324
324
|
```
|
|
325
325
|
|
|
@@ -334,12 +334,12 @@ pluginAssetsRetry({
|
|
|
334
334
|
以下是一个错误示例:
|
|
335
335
|
|
|
336
336
|
```js
|
|
337
|
-
import { someMethod } from
|
|
337
|
+
import { someMethod } from 'utils';
|
|
338
338
|
|
|
339
339
|
pluginAssetsRetry({
|
|
340
340
|
onRetry() {
|
|
341
341
|
// 错误用法,包含了敏感信息
|
|
342
|
-
const privateToken =
|
|
342
|
+
const privateToken = 'a-private-token';
|
|
343
343
|
|
|
344
344
|
// 错误用法,使用了外部的方法
|
|
345
345
|
someMethod(privateToken);
|
|
@@ -351,6 +351,10 @@ pluginAssetsRetry({
|
|
|
351
351
|
|
|
352
352
|
以下场景 Assets Retry 插件可能无法生效:
|
|
353
353
|
|
|
354
|
+
### 同步 script 标签加载的资源
|
|
355
|
+
|
|
356
|
+
`<script src="..."></script>` 标签加载的资源是同步加载的,如果进行重试无法保证资源加载的顺序,因此 Assets Retry 插件不会对同步加载的 script 标签进行重试。只会对 async/defer 的 script 标签进行重试。
|
|
357
|
+
|
|
354
358
|
### 模块联邦
|
|
355
359
|
|
|
356
360
|
对于模块联邦加载的远程模块,你可以使用模块联邦 2.0 的 [@module-federation/retry-plugin](https://www.npmjs.com/package/@module-federation/retry-plugin) 来实现静态资源重试。
|
package/dist/index.cjs
CHANGED
|
@@ -213,25 +213,19 @@ var __webpack_exports__ = {};
|
|
|
213
213
|
if (isRspack) modifyRspackRuntimeModule(module, modifier);
|
|
214
214
|
else modifyWebpackRuntimeModule(module, modifier);
|
|
215
215
|
}
|
|
216
|
-
function pick(obj, keys) {
|
|
217
|
-
return keys.reduce((ret, key)=>{
|
|
218
|
-
if (void 0 !== obj[key]) ret[key] = obj[key];
|
|
219
|
-
return ret;
|
|
220
|
-
}, {});
|
|
221
|
-
}
|
|
222
216
|
class AsyncChunkRetryPlugin {
|
|
223
217
|
getRawRuntimeRetryCode() {
|
|
224
218
|
const { RuntimeGlobals } = core_namespaceObject.rspack;
|
|
225
219
|
const filename = 'asyncChunkRetry';
|
|
226
|
-
const runtimeFilePath = external_node_path_default().join(AsyncChunkRetryPlugin_dirname, 'runtime', this.
|
|
220
|
+
const runtimeFilePath = external_node_path_default().join(AsyncChunkRetryPlugin_dirname, 'runtime', this.minify ? `${filename}.min.js` : `${filename}.js`);
|
|
227
221
|
const rawText = external_node_fs_default().readFileSync(runtimeFilePath, 'utf-8');
|
|
228
222
|
return rawText.replaceAll('__RUNTIME_GLOBALS_REQUIRE__', RuntimeGlobals.require).replaceAll('__RUNTIME_GLOBALS_ENSURE_CHUNK__', RuntimeGlobals.ensureChunk).replaceAll('__RUNTIME_GLOBALS_GET_CHUNK_SCRIPT_FILENAME__', RuntimeGlobals.getChunkScriptFilename).replaceAll('__RUNTIME_GLOBALS_GET_CSS_FILENAME__', RuntimeGlobals.getChunkCssFilename).replaceAll('__RUNTIME_GLOBALS_GET_MINI_CSS_EXTRACT_FILENAME__', '__webpack_require__.miniCssF').replaceAll('__RUNTIME_GLOBALS_RSBUILD_LOAD_STYLESHEET__', '__webpack_require__.rbLoadStyleSheet').replaceAll('__RUNTIME_GLOBALS_PUBLIC_PATH__', RuntimeGlobals.publicPath).replaceAll('__RUNTIME_GLOBALS_LOAD_SCRIPT__', RuntimeGlobals.loadScript).replaceAll('__RETRY_OPTIONS__', serialize_javascript_default()(this.runtimeOptions));
|
|
229
223
|
}
|
|
230
224
|
apply(compiler) {
|
|
231
225
|
compiler.hooks.thisCompilation.tap(this.name, (compilation)=>{
|
|
226
|
+
const isRspack = this.isRspack;
|
|
232
227
|
compilation.hooks.runtimeModule.tap(this.name, (module)=>{
|
|
233
228
|
var _module_constructor;
|
|
234
|
-
const { isRspack } = this.options;
|
|
235
229
|
const constructorName = isRspack ? module.constructorName : null == (_module_constructor = module.constructor) ? void 0 : _module_constructor.name;
|
|
236
230
|
const isCssLoadingRuntimeModule = 'CssLoadingRuntimeModule' === constructorName;
|
|
237
231
|
if (isCssLoadingRuntimeModule) return void modifyRuntimeModule(module, (originSource)=>originSource.replace('var fullhref = __webpack_require__.p + href;', 'var fullhref = __webpack_require__.rbLoadStyleSheet ? __webpack_require__.rbLoadStyleSheet(href, chunkId) : (__webpack_require__.p + href);'), isRspack);
|
|
@@ -243,26 +237,20 @@ var __webpack_exports__ = {};
|
|
|
243
237
|
});
|
|
244
238
|
});
|
|
245
239
|
}
|
|
246
|
-
constructor(options){
|
|
240
|
+
constructor(options, isRspack, minify){
|
|
247
241
|
_define_property(this, "name", 'ASYNC_CHUNK_RETRY_PLUGIN');
|
|
248
|
-
_define_property(this, "
|
|
242
|
+
_define_property(this, "isRspack", void 0);
|
|
243
|
+
_define_property(this, "minify", void 0);
|
|
249
244
|
_define_property(this, "runtimeOptions", void 0);
|
|
250
|
-
this.
|
|
251
|
-
this.
|
|
252
|
-
|
|
253
|
-
'max',
|
|
254
|
-
'onRetry',
|
|
255
|
-
'onSuccess',
|
|
256
|
-
'onFail',
|
|
257
|
-
'addQuery',
|
|
258
|
-
'test',
|
|
259
|
-
'delay'
|
|
260
|
-
]);
|
|
245
|
+
this.runtimeOptions = options;
|
|
246
|
+
this.isRspack = isRspack;
|
|
247
|
+
this.minify = minify;
|
|
261
248
|
}
|
|
262
249
|
}
|
|
263
250
|
const src_dirname = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__));
|
|
264
251
|
const PLUGIN_ASSETS_RETRY_NAME = 'rsbuild:assets-retry';
|
|
265
252
|
function getRuntimeOptions(userOptions) {
|
|
253
|
+
const { inlineScript, minify, ...restOptions } = userOptions;
|
|
266
254
|
const defaultOptions = {
|
|
267
255
|
max: 3,
|
|
268
256
|
type: [
|
|
@@ -272,24 +260,23 @@ var __webpack_exports__ = {};
|
|
|
272
260
|
],
|
|
273
261
|
domain: [],
|
|
274
262
|
crossOrigin: false,
|
|
275
|
-
delay: 0
|
|
263
|
+
delay: 0,
|
|
264
|
+
addQuery: false
|
|
276
265
|
};
|
|
277
266
|
const result = {
|
|
278
267
|
...defaultOptions,
|
|
279
|
-
...
|
|
268
|
+
...restOptions
|
|
280
269
|
};
|
|
281
270
|
if (!Array.isArray(result.type) || 0 === result.type.length) result.type = defaultOptions.type;
|
|
282
271
|
if (!Array.isArray(result.domain) || 0 === result.domain.length) result.domain = defaultOptions.domain;
|
|
283
272
|
if (Array.isArray(result.domain)) result.domain = result.domain.filter(Boolean);
|
|
284
273
|
return result;
|
|
285
274
|
}
|
|
286
|
-
async function getRetryCode(
|
|
275
|
+
async function getRetryCode(runtimeOptions, minify) {
|
|
287
276
|
const filename = 'initialChunkRetry';
|
|
288
|
-
const { minify, inlineScript: _, ...restOptions } = options;
|
|
289
277
|
const runtimeFilePath = external_node_path_default().join(src_dirname, 'runtime', minify ? `${filename}.min.js` : `${filename}.js`);
|
|
290
278
|
const runtimeCode = await external_node_fs_default().promises.readFile(runtimeFilePath, 'utf-8');
|
|
291
|
-
|
|
292
|
-
return `(function(){${runtimeCode}})()`.replace('__RUNTIME_GLOBALS_OPTIONS__', serialize_javascript_default()(runtimeOptions));
|
|
279
|
+
return runtimeCode.replace('__RETRY_OPTIONS__', serialize_javascript_default()(runtimeOptions));
|
|
293
280
|
}
|
|
294
281
|
const pluginAssetsRetry = (userOptions = {})=>({
|
|
295
282
|
name: PLUGIN_ASSETS_RETRY_NAME,
|
|
@@ -297,9 +284,9 @@ var __webpack_exports__ = {};
|
|
|
297
284
|
const { inlineScript = true } = userOptions;
|
|
298
285
|
const getScriptPath = (environment)=>{
|
|
299
286
|
const distDir = environment.config.output.distPath.js;
|
|
300
|
-
return external_node_path_default().posix.join(distDir, "assets-retry.1-
|
|
287
|
+
return external_node_path_default().posix.join(distDir, "assets-retry.1-3-0.js");
|
|
301
288
|
};
|
|
302
|
-
const
|
|
289
|
+
const normalizeOptions = (config)=>{
|
|
303
290
|
const options = {
|
|
304
291
|
...userOptions
|
|
305
292
|
};
|
|
@@ -312,7 +299,9 @@ var __webpack_exports__ = {};
|
|
|
312
299
|
return options;
|
|
313
300
|
};
|
|
314
301
|
if (inlineScript) api.modifyHTMLTags(async ({ headTags, bodyTags }, { environment })=>{
|
|
315
|
-
const
|
|
302
|
+
const options = normalizeOptions(environment.config);
|
|
303
|
+
const runtimeOptions = getRuntimeOptions(options);
|
|
304
|
+
const code = await getRetryCode(runtimeOptions, options.minify);
|
|
316
305
|
headTags.unshift({
|
|
317
306
|
tag: "script",
|
|
318
307
|
attrs: {},
|
|
@@ -342,20 +331,22 @@ var __webpack_exports__ = {};
|
|
|
342
331
|
stage: 'additional'
|
|
343
332
|
}, async ({ sources, compilation, environment })=>{
|
|
344
333
|
const scriptPath = getScriptPath(environment);
|
|
345
|
-
const
|
|
334
|
+
const options = normalizeOptions(environment.config);
|
|
335
|
+
const runtimeOptions = getRuntimeOptions(options);
|
|
336
|
+
const code = await getRetryCode(runtimeOptions, options.minify);
|
|
346
337
|
compilation.emitAsset(scriptPath, new sources.RawSource(code));
|
|
347
338
|
});
|
|
348
339
|
}
|
|
349
340
|
api.modifyBundlerChain(async (chain, { environment })=>{
|
|
350
341
|
const { config, htmlPaths } = environment;
|
|
351
342
|
if (!userOptions || 0 === Object.keys(htmlPaths).length) return;
|
|
352
|
-
const options =
|
|
343
|
+
const options = normalizeOptions(config);
|
|
344
|
+
const runtimeOptions = getRuntimeOptions(options);
|
|
353
345
|
const isRspack = 'rspack' === api.context.bundlerType;
|
|
354
346
|
chain.plugin('async-chunk-retry').use(AsyncChunkRetryPlugin, [
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
347
|
+
runtimeOptions,
|
|
348
|
+
isRspack,
|
|
349
|
+
options.minify
|
|
359
350
|
]);
|
|
360
351
|
});
|
|
361
352
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,96 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { CrossOrigin as CrossOrigin_2 } from '@rsbuild/core';
|
|
2
|
+
import type { RsbuildPlugin } from '@rsbuild/core';
|
|
3
|
+
|
|
4
|
+
declare type AssetsRetryHookContext_2 = {
|
|
5
|
+
url: string;
|
|
6
|
+
times: number;
|
|
7
|
+
domain: string;
|
|
8
|
+
tagName: string;
|
|
9
|
+
isAsyncChunk: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
declare type CompileTimeRetryOptions = {
|
|
13
|
+
/**
|
|
14
|
+
* Whether to inline the runtime JavaScript code of Assets Retry plugin into the HTML file.
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
inlineScript?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Whether to minify the runtime JavaScript code of Assets Retry plugin.
|
|
20
|
+
* @default rsbuildConfig.mode === 'production'
|
|
21
|
+
*/
|
|
22
|
+
minify?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export declare const PLUGIN_ASSETS_RETRY_NAME = "rsbuild:assets-retry";
|
|
26
|
+
|
|
27
|
+
export declare const pluginAssetsRetry: (userOptions?: PluginAssetsRetryOptions) => RsbuildPlugin;
|
|
28
|
+
|
|
29
|
+
export declare type PluginAssetsRetryOptions = RuntimeRetryOptions & CompileTimeRetryOptions;
|
|
30
|
+
|
|
31
|
+
declare type RuntimeRetryOptions = RuntimeRetryOptionsWithDefaultValue & RuntimeRetryOptionsWithoutDefaultValue;
|
|
32
|
+
|
|
33
|
+
declare type RuntimeRetryOptionsWithDefaultValue = {
|
|
34
|
+
/**
|
|
35
|
+
* The maximum number of retries for a single asset.
|
|
36
|
+
* @default 3
|
|
37
|
+
*/
|
|
38
|
+
max?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Used to specify the HTML tag types that need to be retried.
|
|
41
|
+
* @default ['script', 'link', 'img']
|
|
42
|
+
*/
|
|
43
|
+
type?: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Specifies the retry domain when assets fail to load.
|
|
46
|
+
*/
|
|
47
|
+
domain?: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Set the `crossorigin` attribute for tags.
|
|
50
|
+
* @default rsbuildConfig.html.crossorigin
|
|
51
|
+
*/
|
|
52
|
+
crossOrigin?: boolean | CrossOrigin_2;
|
|
53
|
+
/**
|
|
54
|
+
* The delay time between retries. Unit: ms
|
|
55
|
+
* @default 0
|
|
56
|
+
*/
|
|
57
|
+
delay?: number | ((context: AssetsRetryHookContext_2) => number);
|
|
58
|
+
/**
|
|
59
|
+
* The function to add query parameters to the URL of the asset being retried.
|
|
60
|
+
* @param times e.g: 1 -> 2 -> 3
|
|
61
|
+
* @param originalQuery initial request url's query e.g: <script src="https://cdn.com/a.js?version=1"></script> -> "?version=1"
|
|
62
|
+
* @default false
|
|
63
|
+
* @description
|
|
64
|
+
*
|
|
65
|
+
* if set to `true`, `?retry=${times}` will be added to the url.
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* ({ times, originalQuery }) => hasQuery(originalQuery) ? `${getQuery(originalQuery)}&retry=${times}` : `?retry=${times}`
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
addQuery?: boolean | ((context: {
|
|
72
|
+
times: number;
|
|
73
|
+
originalQuery: string;
|
|
74
|
+
}) => string);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
declare type RuntimeRetryOptionsWithoutDefaultValue = {
|
|
78
|
+
/**
|
|
79
|
+
* The test function of the asset to be retried.
|
|
80
|
+
*/
|
|
81
|
+
test?: string | ((url: string) => boolean);
|
|
82
|
+
/**
|
|
83
|
+
* The callback function when the asset is failed to be retried.
|
|
84
|
+
*/
|
|
85
|
+
onFail?: (context: AssetsRetryHookContext_2) => void;
|
|
86
|
+
/**
|
|
87
|
+
* The callback function when the asset is being retried.
|
|
88
|
+
*/
|
|
89
|
+
onRetry?: (context: AssetsRetryHookContext_2) => void;
|
|
90
|
+
/**
|
|
91
|
+
* The callback function when the asset is successfully retried.
|
|
92
|
+
*/
|
|
93
|
+
onSuccess?: (context: AssetsRetryHookContext_2) => void;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export { }
|
package/dist/index.js
CHANGED
|
@@ -189,25 +189,19 @@ function modifyRuntimeModule(module, modifier, isRspack) {
|
|
|
189
189
|
if (isRspack) modifyRspackRuntimeModule(module, modifier);
|
|
190
190
|
else modifyWebpackRuntimeModule(module, modifier);
|
|
191
191
|
}
|
|
192
|
-
function pick(obj, keys) {
|
|
193
|
-
return keys.reduce((ret, key)=>{
|
|
194
|
-
if (void 0 !== obj[key]) ret[key] = obj[key];
|
|
195
|
-
return ret;
|
|
196
|
-
}, {});
|
|
197
|
-
}
|
|
198
192
|
class AsyncChunkRetryPlugin {
|
|
199
193
|
getRawRuntimeRetryCode() {
|
|
200
194
|
const { RuntimeGlobals } = rspack;
|
|
201
195
|
const filename = 'asyncChunkRetry';
|
|
202
|
-
const runtimeFilePath = node_path.join(AsyncChunkRetryPlugin_dirname, 'runtime', this.
|
|
196
|
+
const runtimeFilePath = node_path.join(AsyncChunkRetryPlugin_dirname, 'runtime', this.minify ? `${filename}.min.js` : `${filename}.js`);
|
|
203
197
|
const rawText = node_fs.readFileSync(runtimeFilePath, 'utf-8');
|
|
204
198
|
return rawText.replaceAll('__RUNTIME_GLOBALS_REQUIRE__', RuntimeGlobals.require).replaceAll('__RUNTIME_GLOBALS_ENSURE_CHUNK__', RuntimeGlobals.ensureChunk).replaceAll('__RUNTIME_GLOBALS_GET_CHUNK_SCRIPT_FILENAME__', RuntimeGlobals.getChunkScriptFilename).replaceAll('__RUNTIME_GLOBALS_GET_CSS_FILENAME__', RuntimeGlobals.getChunkCssFilename).replaceAll('__RUNTIME_GLOBALS_GET_MINI_CSS_EXTRACT_FILENAME__', '__webpack_require__.miniCssF').replaceAll('__RUNTIME_GLOBALS_RSBUILD_LOAD_STYLESHEET__', '__webpack_require__.rbLoadStyleSheet').replaceAll('__RUNTIME_GLOBALS_PUBLIC_PATH__', RuntimeGlobals.publicPath).replaceAll('__RUNTIME_GLOBALS_LOAD_SCRIPT__', RuntimeGlobals.loadScript).replaceAll('__RETRY_OPTIONS__', serialize_javascript_default()(this.runtimeOptions));
|
|
205
199
|
}
|
|
206
200
|
apply(compiler) {
|
|
207
201
|
compiler.hooks.thisCompilation.tap(this.name, (compilation)=>{
|
|
202
|
+
const isRspack = this.isRspack;
|
|
208
203
|
compilation.hooks.runtimeModule.tap(this.name, (module)=>{
|
|
209
204
|
var _module_constructor;
|
|
210
|
-
const { isRspack } = this.options;
|
|
211
205
|
const constructorName = isRspack ? module.constructorName : null == (_module_constructor = module.constructor) ? void 0 : _module_constructor.name;
|
|
212
206
|
const isCssLoadingRuntimeModule = 'CssLoadingRuntimeModule' === constructorName;
|
|
213
207
|
if (isCssLoadingRuntimeModule) return void modifyRuntimeModule(module, (originSource)=>originSource.replace('var fullhref = __webpack_require__.p + href;', 'var fullhref = __webpack_require__.rbLoadStyleSheet ? __webpack_require__.rbLoadStyleSheet(href, chunkId) : (__webpack_require__.p + href);'), isRspack);
|
|
@@ -219,26 +213,20 @@ class AsyncChunkRetryPlugin {
|
|
|
219
213
|
});
|
|
220
214
|
});
|
|
221
215
|
}
|
|
222
|
-
constructor(options){
|
|
216
|
+
constructor(options, isRspack, minify){
|
|
223
217
|
_define_property(this, "name", 'ASYNC_CHUNK_RETRY_PLUGIN');
|
|
224
|
-
_define_property(this, "
|
|
218
|
+
_define_property(this, "isRspack", void 0);
|
|
219
|
+
_define_property(this, "minify", void 0);
|
|
225
220
|
_define_property(this, "runtimeOptions", void 0);
|
|
226
|
-
this.
|
|
227
|
-
this.
|
|
228
|
-
|
|
229
|
-
'max',
|
|
230
|
-
'onRetry',
|
|
231
|
-
'onSuccess',
|
|
232
|
-
'onFail',
|
|
233
|
-
'addQuery',
|
|
234
|
-
'test',
|
|
235
|
-
'delay'
|
|
236
|
-
]);
|
|
221
|
+
this.runtimeOptions = options;
|
|
222
|
+
this.isRspack = isRspack;
|
|
223
|
+
this.minify = minify;
|
|
237
224
|
}
|
|
238
225
|
}
|
|
239
226
|
const src_dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
240
227
|
const PLUGIN_ASSETS_RETRY_NAME = 'rsbuild:assets-retry';
|
|
241
228
|
function getRuntimeOptions(userOptions) {
|
|
229
|
+
const { inlineScript, minify, ...restOptions } = userOptions;
|
|
242
230
|
const defaultOptions = {
|
|
243
231
|
max: 3,
|
|
244
232
|
type: [
|
|
@@ -248,24 +236,23 @@ function getRuntimeOptions(userOptions) {
|
|
|
248
236
|
],
|
|
249
237
|
domain: [],
|
|
250
238
|
crossOrigin: false,
|
|
251
|
-
delay: 0
|
|
239
|
+
delay: 0,
|
|
240
|
+
addQuery: false
|
|
252
241
|
};
|
|
253
242
|
const result = {
|
|
254
243
|
...defaultOptions,
|
|
255
|
-
...
|
|
244
|
+
...restOptions
|
|
256
245
|
};
|
|
257
246
|
if (!Array.isArray(result.type) || 0 === result.type.length) result.type = defaultOptions.type;
|
|
258
247
|
if (!Array.isArray(result.domain) || 0 === result.domain.length) result.domain = defaultOptions.domain;
|
|
259
248
|
if (Array.isArray(result.domain)) result.domain = result.domain.filter(Boolean);
|
|
260
249
|
return result;
|
|
261
250
|
}
|
|
262
|
-
async function getRetryCode(
|
|
251
|
+
async function getRetryCode(runtimeOptions, minify) {
|
|
263
252
|
const filename = 'initialChunkRetry';
|
|
264
|
-
const { minify, inlineScript: _, ...restOptions } = options;
|
|
265
253
|
const runtimeFilePath = node_path.join(src_dirname, 'runtime', minify ? `${filename}.min.js` : `${filename}.js`);
|
|
266
254
|
const runtimeCode = await node_fs.promises.readFile(runtimeFilePath, 'utf-8');
|
|
267
|
-
|
|
268
|
-
return `(function(){${runtimeCode}})()`.replace('__RUNTIME_GLOBALS_OPTIONS__', serialize_javascript_default()(runtimeOptions));
|
|
255
|
+
return runtimeCode.replace('__RETRY_OPTIONS__', serialize_javascript_default()(runtimeOptions));
|
|
269
256
|
}
|
|
270
257
|
const pluginAssetsRetry = (userOptions = {})=>({
|
|
271
258
|
name: PLUGIN_ASSETS_RETRY_NAME,
|
|
@@ -273,9 +260,9 @@ const pluginAssetsRetry = (userOptions = {})=>({
|
|
|
273
260
|
const { inlineScript = true } = userOptions;
|
|
274
261
|
const getScriptPath = (environment)=>{
|
|
275
262
|
const distDir = environment.config.output.distPath.js;
|
|
276
|
-
return node_path.posix.join(distDir, "assets-retry.1-
|
|
263
|
+
return node_path.posix.join(distDir, "assets-retry.1-3-0.js");
|
|
277
264
|
};
|
|
278
|
-
const
|
|
265
|
+
const normalizeOptions = (config)=>{
|
|
279
266
|
const options = {
|
|
280
267
|
...userOptions
|
|
281
268
|
};
|
|
@@ -288,7 +275,9 @@ const pluginAssetsRetry = (userOptions = {})=>({
|
|
|
288
275
|
return options;
|
|
289
276
|
};
|
|
290
277
|
if (inlineScript) api.modifyHTMLTags(async ({ headTags, bodyTags }, { environment })=>{
|
|
291
|
-
const
|
|
278
|
+
const options = normalizeOptions(environment.config);
|
|
279
|
+
const runtimeOptions = getRuntimeOptions(options);
|
|
280
|
+
const code = await getRetryCode(runtimeOptions, options.minify);
|
|
292
281
|
headTags.unshift({
|
|
293
282
|
tag: "script",
|
|
294
283
|
attrs: {},
|
|
@@ -318,20 +307,22 @@ const pluginAssetsRetry = (userOptions = {})=>({
|
|
|
318
307
|
stage: 'additional'
|
|
319
308
|
}, async ({ sources, compilation, environment })=>{
|
|
320
309
|
const scriptPath = getScriptPath(environment);
|
|
321
|
-
const
|
|
310
|
+
const options = normalizeOptions(environment.config);
|
|
311
|
+
const runtimeOptions = getRuntimeOptions(options);
|
|
312
|
+
const code = await getRetryCode(runtimeOptions, options.minify);
|
|
322
313
|
compilation.emitAsset(scriptPath, new sources.RawSource(code));
|
|
323
314
|
});
|
|
324
315
|
}
|
|
325
316
|
api.modifyBundlerChain(async (chain, { environment })=>{
|
|
326
317
|
const { config, htmlPaths } = environment;
|
|
327
318
|
if (!userOptions || 0 === Object.keys(htmlPaths).length) return;
|
|
328
|
-
const options =
|
|
319
|
+
const options = normalizeOptions(config);
|
|
320
|
+
const runtimeOptions = getRuntimeOptions(options);
|
|
329
321
|
const isRspack = 'rspack' === api.context.bundlerType;
|
|
330
322
|
chain.plugin('async-chunk-retry').use(AsyncChunkRetryPlugin, [
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
323
|
+
runtimeOptions,
|
|
324
|
+
isRspack,
|
|
325
|
+
options.minify
|
|
335
326
|
]);
|
|
336
327
|
});
|
|
337
328
|
}
|