diff --git a/e2e/cases/assets-retry/index.test.ts b/e2e/cases/assets-retry/index.test.ts index 4dff8d7921..a799c7f1a0 100644 --- a/e2e/cases/assets-retry/index.test.ts +++ b/e2e/cases/assets-retry/index.test.ts @@ -1,5 +1,5 @@ import { dev, gotoPage, proxyConsole } from '@e2e/helper'; -import { expect, test } from '@playwright/test'; +import { expect, type Page, test } from '@playwright/test'; import { type RequestHandler, logger } from '@rsbuild/core'; import { pluginAssetsRetry } from '@rsbuild/plugin-assets-retry'; import type { PluginAssetsRetryOptions } from '@rsbuild/plugin-assets-retry'; @@ -76,6 +76,7 @@ async function createRsbuildWithMiddleware( middleware: RequestHandler | RequestHandler[], options: PluginAssetsRetryOptions, entry?: string, + port?: number, ) { const rsbuild = await dev({ cwd: __dirname, @@ -93,6 +94,9 @@ async function createRsbuildWithMiddleware( }, ], }, + server: { + port, + }, ...(entry ? { source: { entry: { index: entry } }, @@ -264,12 +268,53 @@ function delay(ms = 300) { }); } -test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in successfully retrying async chunk', async ({ +async function proxyPageConsole(page: Page, port: number) { + const onRetryContextList: AssetsRetryHookContext[] = []; + const onSuccessContextList: AssetsRetryHookContext[] = []; + const onFailContextList: AssetsRetryHookContext[] = []; + + const origin = `http://localhost:${port}`; + + page.on('console', async (msg) => { + if (msg.type() !== 'info') { + return; + } + const typeValue = (await msg.args()[0].jsonValue()) as string; + const contextValue = (await msg + .args()[1] + .jsonValue()) as AssetsRetryHookContext; + + if ( + typeValue === 'onRetry' || + typeValue === 'onSuccess' || + typeValue === 'onFail' + ) { + // For snapshot + contextValue.url = contextValue.url?.replace(origin, ''); + contextValue.domain = contextValue.domain?.replace(origin, ''); + } + + if (typeValue === 'onRetry') { + onRetryContextList.push(contextValue); + } else if (typeValue === 'onSuccess') { + onSuccessContextList.push(contextValue); + } else if (typeValue === 'onFail') { + onFailContextList.push(contextValue); + } + }); + return { + onRetryContextList, + onSuccessContextList, + onFailContextList, + }; +} + +test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in successfully retrying initial chunk', async ({ page, }) => { const blockedMiddleware = createBlockMiddleware({ blockNum: 3, - urlPrefix: '/static/js/async/src_AsyncCompTest_tsx.js', + urlPrefix: '/static/js/index.js', }); const rsbuild = await createRsbuildWithMiddleware(blockedMiddleware, { @@ -285,29 +330,11 @@ test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in }, }); - const onRetryContextList: AssetsRetryHookContext[] = []; - const onSuccessContextList: AssetsRetryHookContext[] = []; - const onFailContextList: AssetsRetryHookContext[] = []; - - page.on('console', async (msg) => { - if (msg.type() !== 'info') { - return; - } - const typeValue = await msg.args()[0].jsonValue(); - const contextValue = await msg.args()[1].jsonValue(); - - if (typeValue === 'onRetry') { - onRetryContextList.push(contextValue); - } else if (typeValue === 'onSuccess') { - onSuccessContextList.push(contextValue); - } else if (typeValue === 'onFail') { - onFailContextList.push(contextValue); - } - }); - + const { onRetryContextList, onFailContextList, onSuccessContextList } = + await proxyPageConsole(page, rsbuild.port); await gotoPage(page, rsbuild); - const compTestElement = page.locator('#async-comp-test'); - await expect(compTestElement).toHaveText('Hello AsyncCompTest'); + const compTestElement = page.locator('#comp-test'); + await expect(compTestElement).toHaveText('Hello CompTest'); await delay(); expect({ @@ -318,20 +345,20 @@ test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in onRetryContextList: [ { times: 0, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: '', + url: '/static/js/index.js', tagName: 'script', }, { times: 1, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: '', + url: '/static/js/index.js', tagName: 'script', }, { times: 2, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: '', + url: '/static/js/index.js', tagName: 'script', }, ], @@ -339,8 +366,8 @@ test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in onSuccessContextList: [ { times: 3, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: '', + url: '/static/js/index.js', tagName: 'script', }, ], @@ -348,11 +375,11 @@ test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in await rsbuild.close(); }); -test('@rsbuild/plugin-assets-retry onRetry and onFail options should work in failed retrying async chunk', async ({ +test('@rsbuild/plugin-assets-retry onRetry and onSuccess options should work in successfully retrying async chunk', async ({ page, }) => { const blockedMiddleware = createBlockMiddleware({ - blockNum: 100, + blockNum: 3, urlPrefix: '/static/js/async/src_AsyncCompTest_tsx.js', }); @@ -369,24 +396,153 @@ test('@rsbuild/plugin-assets-retry onRetry and onFail options should work in fai }, }); - const onRetryContextList: AssetsRetryHookContext[] = []; - const onSuccessContextList: AssetsRetryHookContext[] = []; - const onFailContextList: AssetsRetryHookContext[] = []; - page.on('console', async (msg) => { - if (msg.type() !== 'info') { - return; - } - const typeValue = await msg.args()?.[0].jsonValue(); - const contextValue = await msg.args()?.[1].jsonValue(); + const { onRetryContextList, onFailContextList, onSuccessContextList } = + await proxyPageConsole(page, rsbuild.port); - if (typeValue === 'onRetry') { - onRetryContextList.push(contextValue); - } else if (typeValue === 'onSuccess') { - onSuccessContextList.push(contextValue); - } else if (typeValue === 'onFail') { - onFailContextList.push(contextValue); - } + await gotoPage(page, rsbuild); + const compTestElement = page.locator('#async-comp-test'); + await expect(compTestElement).toHaveText('Hello AsyncCompTest'); + await delay(); + + expect({ + onRetryContextList, + onFailContextList, + onSuccessContextList, + }).toMatchObject({ + onRetryContextList: [ + { + times: 0, + domain: '', + url: '/static/js/async/src_AsyncCompTest_tsx.js', + tagName: 'script', + }, + { + times: 1, + domain: '', + url: '/static/js/async/src_AsyncCompTest_tsx.js', + tagName: 'script', + }, + { + times: 2, + domain: '', + url: '/static/js/async/src_AsyncCompTest_tsx.js', + tagName: 'script', + }, + ], + onFailContextList: [], + onSuccessContextList: [ + { + times: 3, + domain: '', + url: '/static/js/async/src_AsyncCompTest_tsx.js', + tagName: 'script', + }, + ], }); + await rsbuild.close(); +}); + +test('@rsbuild/plugin-assets-retry onRetry and onFail options should work in failed retrying initial chunk', async ({ + page, +}) => { + const blockedMiddleware = createBlockMiddleware({ + blockNum: 100, + urlPrefix: '/static/js/index.js', + }); + + const rsbuild = await createRsbuildWithMiddleware( + blockedMiddleware, + { + minify: true, + domain: ['http://localhost:3030', 'http://a.com', 'http://b.com'], + inlineScript: true, + onRetry(context) { + console.info('onRetry', context); + }, + onSuccess(context) { + console.info('onSuccess', context); + }, + onFail(context) { + console.info('onFail', context); + }, + }, + undefined, + 3030, + ); + + const { onRetryContextList, onFailContextList, onSuccessContextList } = + await proxyPageConsole(page, rsbuild.port); + + await gotoPage(page, rsbuild); + await delay(); + + expect({ + onRetryContextList, + onFailContextList, + onSuccessContextList, + }).toMatchObject({ + onRetryContextList: [ + { + times: 0, + domain: '', + url: '/static/js/index.js', + tagName: 'script', + }, + { + times: 1, + domain: 'http://a.com', + url: 'http://a.com/static/js/index.js', + tagName: 'script', + }, + { + times: 2, + domain: 'http://b.com', + url: 'http://b.com/static/js/index.js', + tagName: 'script', + }, + ], + onFailContextList: [ + { + times: 3, + domain: '', + url: '/static/js/index.js', + tagName: 'script', + }, + ], + onSuccessContextList: [], + }); + await rsbuild.close(); +}); + +test('@rsbuild/plugin-assets-retry onRetry and onFail options should work in failed retrying async chunk', async ({ + page, +}) => { + const blockedMiddleware = createBlockMiddleware({ + blockNum: 100, + urlPrefix: '/static/js/async/src_AsyncCompTest_tsx.js', + }); + + const rsbuild = await createRsbuildWithMiddleware( + blockedMiddleware, + { + minify: true, + domain: ['http://localhost:3031', 'http://a.com', 'http://b.com'], + onRetry(context) { + console.info('onRetry', context); + }, + onSuccess(context) { + console.info('onSuccess', context); + }, + onFail(context) { + console.info('onFail', context); + }, + }, + undefined, + 3031, + ); + + const { onRetryContextList, onFailContextList, onSuccessContextList } = + await proxyPageConsole(page, rsbuild.port); await gotoPage(page, rsbuild); const compTestElement = page.locator('#async-comp-test-error'); @@ -403,28 +559,28 @@ test('@rsbuild/plugin-assets-retry onRetry and onFail options should work in fai onRetryContextList: [ { times: 0, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: '', + url: '/static/js/async/src_AsyncCompTest_tsx.js', tagName: 'script', }, { times: 1, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: 'http://a.com', + url: 'http://a.com/static/js/async/src_AsyncCompTest_tsx.js', tagName: 'script', }, { times: 2, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: 'http://b.com', + url: 'http://b.com/static/js/async/src_AsyncCompTest_tsx.js', tagName: 'script', }, ], onFailContextList: [ { times: 3, - domain: '/', - url: '/static/js/async/src_AsyncCompTest_tsx.js', + domain: '', + url: '/static/js/async/src_AsyncCompTest_tsx.js', tagName: 'script', }, ], diff --git a/packages/plugin-assets-retry/src/runtime/asyncChunkRetry.ts b/packages/plugin-assets-retry/src/runtime/asyncChunkRetry.ts index 8f0f103d67..c5ab4c999e 100644 --- a/packages/plugin-assets-retry/src/runtime/asyncChunkRetry.ts +++ b/packages/plugin-assets-retry/src/runtime/asyncChunkRetry.ts @@ -61,7 +61,7 @@ function findCurrentDomain(url: string) { break; } } - return domain || url; + return domain || window.origin; } function findNextDomain(url: string) { @@ -99,14 +99,10 @@ function getNextRetryUrl( existRetryTimes: number, nextDomain: string, originalSrcUrl: string, - originalScriptFilename: string, ) { return ( - cleanUrl( - nextDomain + - (nextDomain[nextDomain.length - 1] === '/' ? '' : '/') + - originalScriptFilename, - ) + getUrlRetryQuery(existRetryTimes, getQueryFromUrl(originalSrcUrl)) + cleanUrl(nextDomain + originalSrcUrl) + + getUrlRetryQuery(existRetryTimes, getQueryFromUrl(originalSrcUrl)) ); } @@ -121,17 +117,12 @@ function initRetry(chunkId: string): Retry { __RUNTIME_GLOBALS_PUBLIC_PATH__ + originalScriptFilename; const existRetryTimes = 1; - const nextDomain = config.domain?.[0] ?? __RUNTIME_GLOBALS_PUBLIC_PATH__; + const nextDomain = config.domain?.[0] ?? window.origin; return { existRetryTimes, nextDomain, - nextRetryUrl: getNextRetryUrl( - existRetryTimes, - nextDomain, - originalSrcUrl, - originalScriptFilename, - ), + nextRetryUrl: getNextRetryUrl(existRetryTimes, nextDomain, originalSrcUrl), originalScriptFilename, originalSrcUrl, @@ -156,7 +147,6 @@ function nextRetry(chunkId: string): Retry { existRetryTimes, nextDomain, originalSrcUrl, - originalScriptFilename, ), originalScriptFilename, diff --git a/packages/plugin-assets-retry/src/runtime/initialChunkRetry.ts b/packages/plugin-assets-retry/src/runtime/initialChunkRetry.ts index 595fff20a6..f3d8b50737 100644 --- a/packages/plugin-assets-retry/src/runtime/initialChunkRetry.ts +++ b/packages/plugin-assets-retry/src/runtime/initialChunkRetry.ts @@ -30,7 +30,7 @@ function findCurrentDomain(url: string, domainList: string[]) { break; } } - return domain || url; + return domain || window.origin; } function findNextDomain(url: string, domainList: string[]) {