{"id":25726383,"url":"https://github.com/rspack-contrib/rsbuild-plugin-assets-retry","last_synced_at":"2025-05-08T00:18:40.778Z","repository":{"id":279227370,"uuid":"938056109","full_name":"rspack-contrib/rsbuild-plugin-assets-retry","owner":"rspack-contrib","description":"An Rsbuild plugin to automatically resend requests when static assets fail to load.","archived":false,"fork":false,"pushed_at":"2025-03-10T13:39:33.000Z","size":75,"stargazers_count":5,"open_issues_count":4,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-08T00:18:33.438Z","etag":null,"topics":["rsbuild","rsbuild-plugin","rspack","rstack"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rspack-contrib.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-24T10:56:06.000Z","updated_at":"2025-03-19T13:18:21.000Z","dependencies_parsed_at":"2025-02-24T14:27:31.348Z","dependency_job_id":null,"html_url":"https://github.com/rspack-contrib/rsbuild-plugin-assets-retry","commit_stats":null,"previous_names":["rspack-contrib/rsbuild-plugin-assets-retry"],"tags_count":1,"template":false,"template_full_name":"rspack-contrib/rsbuild-plugin-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-assets-retry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-assets-retry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-assets-retry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rspack-contrib%2Frsbuild-plugin-assets-retry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rspack-contrib","download_url":"https://codeload.github.com/rspack-contrib/rsbuild-plugin-assets-retry/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252973734,"owners_count":21834132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rsbuild","rsbuild-plugin","rspack","rstack"],"created_at":"2025-02-25T23:02:29.880Z","updated_at":"2025-05-08T00:18:40.767Z","avatar_url":"https://github.com/rspack-contrib.png","language":"TypeScript","funding_links":[],"categories":["Plugins"],"sub_categories":["Rsbuild Plugins"],"readme":"# @rsbuild/plugin-assets-retry\n\nAn Rsbuild plugin to automatically resend requests when static assets fail to load.\n\n\u003cp\u003e\n  \u003ca href=\"https://npmjs.com/package/@rsbuild/plugin-assets-retry\"\u003e\n   \u003cimg src=\"https://img.shields.io/npm/v/@rsbuild/plugin-assets-retry?style=flat-square\u0026colorA=564341\u0026colorB=EDED91\" alt=\"npm version\" /\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square\u0026colorA=564341\u0026colorB=EDED91\" alt=\"license\" /\u003e\n  \u003ca href=\"https://npmcharts.com/compare/@rsbuild/plugin-assets-retry?minimal=true\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/@rsbuild/plugin-assets-retry.svg?style=flat-square\u0026colorA=564341\u0026colorB=EDED91\" alt=\"downloads\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nEnglish | [简体中文](./README.zh-CN.md)\n\n## Quick start\n\n### Install plugin\n\nYou can install the plugin using the following command:\n\n```bash\n# npm\nnpm add @rsbuild/plugin-assets-retry -D\n\n# yarn\nyarn add @rsbuild/plugin-assets-retry -D\n\n# pnpm\npnpm add @rsbuild/plugin-assets-retry -D\n\n# bun\nbun add @rsbuild/plugin-assets-retry -D\n```\n\n### Register plugin\n\nYou can register the plugin in the `rsbuild.config.ts` file:\n\n```ts\nimport { pluginAssetsRetry } from \"@rsbuild/plugin-assets-retry\";\n\nexport default {\n  plugins: [pluginAssetsRetry()],\n};\n```\n\n## Options\n\nYou can configure the retry behavior for assets retry through the options.\n\n- **Type:**\n\n```ts\ntype AssetsRetryHookContext = {\n  times: number;\n  domain: string;\n  url: string;\n  tagName: string;\n  isAsyncChunk: boolean;\n};\n\ntype AssetsRetryOptions = {\n  type?: string[];\n  domain?: string[];\n  max?: number;\n  test?: string | ((url: string) =\u003e boolean);\n  crossOrigin?: boolean | \"anonymous\" | \"use-credentials\";\n  inlineScript?: boolean;\n  delay?: number | ((context: AssetsRetryHookContext) =\u003e number);\n  onRetry?: (context: AssetsRetryHookContext) =\u003e void;\n  onSuccess?: (context: AssetsRetryHookContext) =\u003e void;\n  onFail?: (context: AssetsRetryHookContext) =\u003e void;\n};\n```\n\n- **Default:**\n\n```ts\nconst defaultAssetsRetryOptions = {\n  type: [\"script\", \"link\", \"img\"],\n  domain: [],\n  max: 3,\n  test: \"\",\n  crossOrigin: false,\n  delay: 0,\n  onRetry: () =\u003e {},\n  onSuccess: () =\u003e {},\n  onFail: () =\u003e {},\n};\n```\n\n### domain\n\n- **Type:** `string[]`\n- **Default:** `[]`\n\nSpecifies the retry domain when assets fail to load. In the `domain` array, the first item is the default domain of static assets, and the following items are backup domains. When a asset request for a domain fails, Rsbuild will find that domain in the array and replace it with the next domain in the array.\n\nFor example:\n\n```js\n// rsbuild.config.ts\ndefineConfig({\n  plugins: [\n    pluginAssetsRetry({\n      domain: [\"cdn1.com\", \"cdn2.com\", \"cdn3.com\"],\n    })\n  ],\n  output: {\n    assetPrefix: \"https://cdn1.com\", // or \"//cdn1.com\"\n  },\n});\n```\n\nAfter adding the above configuration, when assets fail to load from the `cdn1.com` domain, the request domain will automatically fallback to `cdn2.com`.\n\nIf the assets request for `cdn2.com` also fails, the request will fallback to `cdn3.com`.\n\n### type\n\n- **Type:** `string[]`\n- **Default:** `['script', 'link', 'img']`\n\nUsed to specify the HTML tag types that need to be retried. By default, script tags, link tags, and img tags are processed, corresponding to JS code, CSS code, and images.\n\nFor example, only script tags and link tags are processed:\n\n```js\npluginAssetsRetry({\n  type: [\"script\", \"link\"],\n});\n```\n\n### max\n\n- **Type:** `number`\n- **Default:** `3`\n\nThe maximum number of retries for a single asset. For example:\n\n```js\npluginAssetsRetry({\n  max: 5,\n});\n```\n\n### test\n\n- **Type:** `string | ((url: string) =\u003e boolean) | undefined`\n- **Default:** `undefined`\n\nThe test function of the asset to be retried. For example:\n\n```js\npluginAssetsRetry({\n  test: /cdn\\.example\\.com/,\n});\n```\n\n### crossOrigin\n\n- **Type:** `undefined | boolean | 'anonymous' | 'use-credentials'`\n- **Default:** `same as html.crossorigin`\n\nWhen initiating a retry for assets, Rsbuild will recreate the `\u003cscript\u003e` tags. This option allows you to set the `crossorigin` attribute for these tags.\n\nBy default, the value of `crossOrigin` will be consistent with the `html.crossorigin` configuration, so no additional configuration is required. If you need to configure the recreated tags separately, you can use this option, for example:\n\n```js\npluginAssetsRetry({\n  crossOrigin: true,\n});\n```\n\n### onRetry\n\n- **Type:** `undefined | (context: AssetsRetryHookContext) =\u003e void`\n\nThe callback function when the asset is being retried. For example:\n\n```js\npluginAssetsRetry({\n  onRetry: ({ times, domain, url, tagName, isAsyncChunk }) =\u003e {\n    console.log(\n      `Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`\n    );\n  },\n});\n```\n\n### onSuccess\n\n- **Type:** `undefined | (context: AssetsRetryHookContext) =\u003e void`\n\nThe callback function when the asset is successfully retried. For example:\n\n```js\npluginAssetsRetry({\n  onSuccess: ({ times, domain, url, tagName, isAsyncChunk }) =\u003e {\n    console.log(\n      `Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`\n    );\n  },\n});\n```\n\n### onFail\n\n- **Type:** `undefined | (context: AssetsRetryHookContext) =\u003e void`\n\nThe callback function when the asset is failed to be retried. For example:\n\n```js\npluginAssetsRetry({\n  onFail: ({ times, domain, url, tagName, isAsyncChunk }) =\u003e {\n    console.log(\n      `Retry ${times} times, domain: ${domain}, url: ${url}, tagName: ${tagName}, isAsyncChunk: ${isAsyncChunk}`\n    );\n  },\n});\n```\n\n### addQuery\n\n- **Type:**\n\n```ts\ntype AddQuery =\n  | boolean\n  | ((context: { times: number; originalQuery: string }) =\u003e string);\n```\n\n- **Default:** `false`\n\nWhether to add query when retrying resources, so as to avoid being affected by browser and CDN caches on the retry results.\n\nWhen set to `true`, `retry=${times}` will be added to the query when requesting, and requests will be made in sequence according to `retry=1`, `retry=2`, `retry=3` etc, for example:\n\n1. Assume that the requested asset is `https://js.cdn.net/foo.js`. If the request fails, it will automatically retry `https://js.cdn.net/foo.js?retry=${times}`\n\n2. Assume that the requested asset is `https://js.cdn.net/foo.js?version=1`. If the request fails, it will automatically retry `https://js.cdn.net/foo.js?version=1\u0026retry=${times}`\n\nWhen you want to customize query, you can pass a function, for example:\n\n- **Example:** All assets requested do not contain query:\n\n```js\npluginAssetsRetry({\n  addQuery: ({ times }) =\u003e {\n    return times === 3\n      ? `?retryCount=${times}\u0026isLast=1`\n      : `?retryCount=${times}`;\n  },\n});\n```\n\n- **Example:** If there is a query in some of the requested assets, you can read it with `originalQuery`:\n\n```js\npluginAssetsRetry({\n  addQuery: ({ times, originalQuery }) =\u003e {\n    const query =\n      times === 3 ? `retryCount=${times}\u0026isLast=1` : `retryCount=${times}`;\n    return originalQuery ? `${originalQuery}\u0026${query}` : `?${query}`;\n  },\n});\n```\n\n### inlineScript\n\n- **Type:** `boolean`\n- **Default:** `true`\n\nWhether to inline the runtime JavaScript code of Assets Retry plugin into the HTML file.\n\nIf you don't want to insert the code in the HTML file, you can set `inlineScript` to `false`:\n\n```js\npluginAssetsRetry({\n  inlineScript: false,\n});\n```\n\nAfter adding the above configuration, the runtime code of Assets Retry plugin will be extracted into a separate `assets-retry.[version].js` file and output to the dist directory.\n\nThe downside is that `assets-retry.[version].js` itself may fail to load. If this happens, the assets retry will not work. Therefore, we prefer to inline the runtime code into the HTML file.\n\n### minify\n\n- **Type:** `boolean`\n- **Default:** `process.env.NODE_ENV === 'production'`\n\nConfigure whether to enable code minification for runtime JavaScript code.\n\nBy default, it will be affected by the [output.minify](/config/output/minify) configuration.\n\n```js\npluginAssetsRetry({\n  minify: true,\n});\n```\n\n### delay\n\n- **Type:** `number | ((context: AssetsRetryHookContext) =\u003e number)`\n- **Default:** `0`\n\nThe delay time (in milliseconds) before retrying a failed asset.\n\nYou can pass a number:\n\n```js\n// Delay 1s before retrying\npluginAssetsRetry({\n  delay: 1000,\n});\n```\n\nOr pass a function that receives `AssetsRetryHookContext` and returns the delay time:\n\n```js\n// Calculate delay based on retry attempts\npluginAssetsRetry({\n  delay: (ctx) =\u003e (ctx.times + 1) * 1000,\n});\n```\n\n## Notes\n\nWhen 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:\n\n- Avoid configuring sensitive information in Assets Retry plugin, such as internal tokens.\n- Avoid referencing variables or methods outside of `onRetry`, `onSuccess`, and `onFail`.\n- Avoid using syntax with compatibility issues in `onRetry`, `onSuccess` and `onFail` as these functions are inlined directly into the HTML.\n\nHere's an example of incorrect usage:\n\n```js\nimport { someMethod } from \"utils\";\n\npluginAssetsRetry({\n  onRetry() {\n    // Incorrect usage, includes sensitive information\n    const privateToken = \"a-private-token\";\n\n    // Incorrect usage, uses an external method\n    someMethod(privateToken);\n  },\n});\n```\n\n## Limitation\n\nAssets Retry plugin may not work in the following scenarios:\n\n### Module Federation\n\nFor 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.\n\n### Micro-frontend\n\nIf your project is a micro-frontend application (such as a Garfish sub-application), the assets retry may not work because micro-frontend sub-applications are typically not loaded directly based on the `\u003cscript\u003e` tag.\n\nIf you need to retry assets in micro-frontend scenarios, please contact the developers of the micro-frontend framework to find a solution.\n\n### Assets in custom templates\n\nAssets Retry plugin listens to the page error event to know whether the current resource fails to load and needs to be retried. Therefore, if the resource in the custom template is executed earlier than Assets Retry plugin, then Assets Retry plugin cannot listen to the event that the resource fails to load, so it will not be retried.\n\nIf you want Assets Retry plugin to work on resources in custom templates, you can refer to [Custom Insertion Example](https://github.com/rspack-contrib/html-rspack-plugin/tree/main/examples/custom-insertion-position) to modify [html.inject](/config/html/inject) configuration and custom template.\n\n```diff\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    \u003ctitle\u003ecustom template\u003c/title\u003e\n+   \u003c%= htmlPlugin.tags.headTags %\u003e\n    \u003cscript src=\"https://example.com/assets/a.js\"\u003e\u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cdiv id=\"root\" /\u003e\n+    \u003c%= htmlPlugin.tags.bodyTags %\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## License\n\n[MIT](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frspack-contrib%2Frsbuild-plugin-assets-retry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frspack-contrib%2Frsbuild-plugin-assets-retry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frspack-contrib%2Frsbuild-plugin-assets-retry/lists"}