diff --git a/packages/nuxt/src/app/composables/router.ts b/packages/nuxt/src/app/composables/router.ts index 5c58ff8646..1446bddbf2 100644 --- a/packages/nuxt/src/app/composables/router.ts +++ b/packages/nuxt/src/app/composables/router.ts @@ -6,7 +6,7 @@ import { hasProtocol, joinURL, parseURL } from 'ufo' import { useNuxtApp, useRuntimeConfig } from '../nuxt' import type { NuxtError } from './error' -import { createError } from './error' +import { createError, showError } from './error' import { useState } from './state' import type { PageMeta } from '#app' @@ -155,10 +155,16 @@ export const abortNavigation = (err?: string | Partial) => { if (process.dev && !isProcessingMiddleware()) { throw new Error('abortNavigation() is only usable inside a route middleware handler.') } - if (err) { - throw createError(err) + + if (!err) { return false } + + err = createError(err) + + if (err.fatal) { + useNuxtApp().runWithContext(() => showError(err as NuxtError)) } - return false + + throw err } export const setPageLayout = (layout: string) => { diff --git a/test/basic.test.ts b/test/basic.test.ts index e221b84436..c44f5569d0 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -710,6 +710,14 @@ describe('middlewares', () => { expect(res.status).toEqual(401) }) + it('should allow aborting navigation fatally on client-side', async () => { + const html = await $fetch('/middleware-abort') + expect(html).not.toContain('This is the error page') + const page = await createPage('/middleware-abort') + await page.waitForLoadState('networkidle') + expect(await page.innerHTML('body')).toContain('This is the error page') + }) + it('should inject auth', async () => { const html = await $fetch('/auth') diff --git a/test/fixtures/basic/pages/middleware-abort.vue b/test/fixtures/basic/pages/middleware-abort.vue new file mode 100644 index 0000000000..bb97403eb6 --- /dev/null +++ b/test/fixtures/basic/pages/middleware-abort.vue @@ -0,0 +1,18 @@ + + +