From 1c26e0714115d69641cfcaf60680be98f1b558e9 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Thu, 22 Sep 2022 14:54:34 +0100 Subject: [PATCH] feat(nuxt): support `redirect` within page metadata (#7746) --- packages/nuxt/src/pages/runtime/composables.ts | 14 +++++++++++++- packages/nuxt/src/pages/utils.ts | 1 + packages/schema/src/types/hooks.ts | 3 ++- test/basic.test.ts | 10 ++++++++++ test/fixtures/basic/pages/index.vue | 4 ++++ test/fixtures/basic/pages/redirect.vue | 11 +++++++++++ 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/basic/pages/redirect.vue diff --git a/packages/nuxt/src/pages/runtime/composables.ts b/packages/nuxt/src/pages/runtime/composables.ts index 737c24f509..2b6e0e6730 100644 --- a/packages/nuxt/src/pages/runtime/composables.ts +++ b/packages/nuxt/src/pages/runtime/composables.ts @@ -1,8 +1,20 @@ import { KeepAliveProps, TransitionProps, UnwrapRef } from 'vue' -import type { RouteLocationNormalizedLoaded } from 'vue-router' +import type { RouteLocationNormalizedLoaded, RouteRecordRedirectOption } from 'vue-router' export interface PageMeta { [key: string]: any + /** + * Where to redirect if the route is directly matched. The redirection happens + * before any navigation guard and triggers a new navigation with the new + * target location. + */ + redirect?: RouteRecordRedirectOption + /** + * Aliases for the record. Allows defining extra paths that will behave like a + * copy of the record. Allows having paths shorthands like `/users/:id` and + * `/u/:id`. All `alias` and `path` values must share the same params. + */ + alias?: string | string[] pageTransition?: boolean | TransitionProps layoutTransition?: boolean | TransitionProps key?: false | string | ((route: RouteLocationNormalizedLoaded) => string) diff --git a/packages/nuxt/src/pages/utils.ts b/packages/nuxt/src/pages/utils.ts index 1556daf787..2bc25b3f0a 100644 --- a/packages/nuxt/src/pages/utils.ts +++ b/packages/nuxt/src/pages/utils.ts @@ -243,6 +243,7 @@ export function normalizeRoutes (routes: NuxtPage[], metaImports: Set = children: route.children ? normalizeRoutes(route.children, metaImports).routes : [], meta: route.meta ? `{...(${metaImportName} || {}), ...${JSON.stringify(route.meta)}}` : metaImportName, alias: aliasCode, + redirect: route.redirect ? JSON.stringify(route.redirect) : `${metaImportName}?.redirect || undefined`, component: genDynamicImport(file, { interopDefault: true }) } })) diff --git a/packages/schema/src/types/hooks.ts b/packages/schema/src/types/hooks.ts index 1e3d5d036c..b0df1adeb8 100644 --- a/packages/schema/src/types/hooks.ts +++ b/packages/schema/src/types/hooks.ts @@ -43,7 +43,8 @@ export type NuxtPage = { path: string file: string meta?: Record - alias?: string[] + alias?: string[] | string + redirect?: string children?: NuxtPage[] } diff --git a/test/basic.test.ts b/test/basic.test.ts index 9116bc51db..2fe9c019db 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -55,6 +55,16 @@ describe('pages', () => { await expectNoClientErrors('/') }) + it('respects aliases in page metadata', async () => { + const html = await $fetch('/some-alias') + expect(html).toContain('Hello Nuxt 3!') + }) + + it('respects redirects in page metadata', async () => { + const { headers } = await fetch('/redirect', { redirect: 'manual' }) + expect(headers.get('location')).toEqual('/') + }) + it('render 404', async () => { const html = await $fetch('/not-found') diff --git a/test/fixtures/basic/pages/index.vue b/test/fixtures/basic/pages/index.vue index 69856bb302..eb335bfca5 100644 --- a/test/fixtures/basic/pages/index.vue +++ b/test/fixtures/basic/pages/index.vue @@ -28,6 +28,10 @@ setupDevtoolsPlugin({}, () => {}) const config = useRuntimeConfig() +definePageMeta({ + alias: '/some-alias' +}) + // reset title template example useHead({ titleTemplate: '' diff --git a/test/fixtures/basic/pages/redirect.vue b/test/fixtures/basic/pages/redirect.vue new file mode 100644 index 0000000000..3ef5f992d4 --- /dev/null +++ b/test/fixtures/basic/pages/redirect.vue @@ -0,0 +1,11 @@ + + +