diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index e90befa4d6..a903987a01 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -375,7 +375,9 @@ export function createNuxtApp (options: CreateOptions) { if (chunkErrorEvent) { window.addEventListener(chunkErrorEvent, (event) => { nuxtApp.callHook('app:chunkError', { error: (event as Event & { payload: Error }).payload }) - event.preventDefault() + if (nuxtApp.isHydrating || event.payload.message.includes('Unable to preload CSS')) { + event.preventDefault() + } }) } window.useNuxtApp = window.useNuxtApp || useNuxtApp diff --git a/packages/nuxt/src/app/plugins/chunk-reload.client.ts b/packages/nuxt/src/app/plugins/chunk-reload.client.ts index c43d433428..06cd15841c 100644 --- a/packages/nuxt/src/app/plugins/chunk-reload.client.ts +++ b/packages/nuxt/src/app/plugins/chunk-reload.client.ts @@ -10,7 +10,7 @@ export default defineNuxtPlugin({ const router = useRouter() const config = useRuntimeConfig() - const chunkErrors = new Set() + const chunkErrors = new Set() router.beforeEach(() => { chunkErrors.clear() }) nuxtApp.hook('app:chunkError', ({ error }) => { chunkErrors.add(error) }) @@ -26,7 +26,7 @@ export default defineNuxtPlugin({ }) router.onError((error, to) => { - if (chunkErrors.has(error) || error.message.includes('Failed to fetch dynamically imported module')) { + if (chunkErrors.has(error)) { reloadAppAtPath(to) } }) diff --git a/test/basic.test.ts b/test/basic.test.ts index a09ae8de8f..9b9100f07e 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -1165,16 +1165,29 @@ describe('errors', () => { // TODO: need to create test for webpack it.runIf(!isDev())('should handle chunk loading errors', async () => { - const { page, consoleLogs } = await renderPage('/') + const { page, consoleLogs } = await renderPage() + await page.route(/\.css/, route => route.abort('timedout')) // verify CSS link preload failure doesn't break the page + await page.goto(url('/')) + await page.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/' && !window.useNuxtApp?.().isHydrating) + + const initialLogs = consoleLogs.map(c => c.text).join('') + expect(initialLogs).toContain('caught chunk load error') + consoleLogs.length = 0 + await page.getByText('Increment state').click() await page.getByText('Increment state').click() expect(await page.innerText('div')).toContain('Some value: 3') await page.route(/.*/, route => route.abort('timedout'), { times: 1 }) await page.getByText('Chunk error').click() + await page.waitForURL(url('/chunk-error')) - expect(consoleLogs.map(c => c.text).join('')).toContain('Failed to load resource') - expect(await page.innerText('div')).toContain('Chunk error page') + + const logs = consoleLogs.map(c => c.text).join('') + expect(logs).toContain('caught chunk load error') + expect(logs).toContain('Failed to load resource') + await page.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/chunk-error') + expect(await page.innerText('div')).toContain('Chunk error page') await page.locator('div').getByText('State: 3').waitFor() await page.close() diff --git a/test/fixtures/basic/plugins/chunk-error.ts b/test/fixtures/basic/plugins/chunk-error.ts new file mode 100644 index 0000000000..e23e5ecdd9 --- /dev/null +++ b/test/fixtures/basic/plugins/chunk-error.ts @@ -0,0 +1,5 @@ +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.hook('app:chunkError', () => { + console.log('caught chunk load error') + }) +})