fix(nuxt): ensure getRouteRules works with nitro signature (#30277)

This commit is contained in:
Daniel Roe 2024-12-16 20:51:18 +00:00 committed by GitHub
parent cb169b52d5
commit 48e50c030a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 34 additions and 9 deletions

View File

@ -1,6 +1,8 @@
import type { MatcherExport, RouteMatcher } from 'radix3' import type { MatcherExport, RouteMatcher } from 'radix3'
import { createMatcherFromExport, createRouter as createRadixRouter, toRouteMatcher } from 'radix3' import { createMatcherFromExport, createRouter as createRadixRouter, toRouteMatcher } from 'radix3'
import { defu } from 'defu' import { defu } from 'defu'
import type { H3Event } from 'h3'
import type { NitroRouteRules } from 'nitro/types'
import { useNuxtApp, useRuntimeConfig } from '../nuxt' import { useNuxtApp, useRuntimeConfig } from '../nuxt'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import { appManifest as isAppManifestEnabled } from '#build/nuxt.config.mjs' import { appManifest as isAppManifestEnabled } from '#build/nuxt.config.mjs'
@ -52,13 +54,18 @@ export function getAppManifest (): Promise<NuxtAppManifest> {
} }
/** @since 3.7.4 */ /** @since 3.7.4 */
export async function getRouteRules (url: string) { export async function getRouteRules (event: H3Event): Promise<NitroRouteRules>
export async function getRouteRules (options: { path: string }): Promise<Record<string, any>>
/** @deprecated use `getRouteRules({ path })` instead */
export async function getRouteRules (url: string): Promise<Record<string, any>>
export async function getRouteRules (arg: string | H3Event | { path: string }) {
const path = typeof arg === 'string' ? arg : arg.path
if (import.meta.server) { if (import.meta.server) {
useNuxtApp().ssrContext!._preloadManifest = true useNuxtApp().ssrContext!._preloadManifest = true
const _routeRulesMatcher = toRouteMatcher( const _routeRulesMatcher = toRouteMatcher(
createRadixRouter({ routes: useRuntimeConfig().nitro!.routeRules }), createRadixRouter({ routes: useRuntimeConfig().nitro!.routeRules }),
) )
return defu({} as Record<string, any>, ..._routeRulesMatcher.matchAll(url).reverse()) return defu({} as Record<string, any>, ..._routeRulesMatcher.matchAll(path).reverse())
} }
await getAppManifest() await getAppManifest()
if (!matcher) { if (!matcher) {
@ -66,7 +73,7 @@ export async function getRouteRules (url: string) {
return {} return {}
} }
try { try {
return defu({} as Record<string, any>, ...matcher.matchAll(url).reverse()) return defu({} as Record<string, any>, ...matcher.matchAll(path).reverse())
} catch (e) { } catch (e) {
console.error('[nuxt] Error matching route rules.', e) console.error('[nuxt] Error matching route rules.', e)
return {} return {}

View File

@ -94,7 +94,7 @@ export async function isPrerendered (url = useRoute().path) {
return true return true
} }
return nuxtApp.runWithContext(async () => { return nuxtApp.runWithContext(async () => {
const rules = await getRouteRules(url) const rules = await getRouteRules({ path: url })
return !!rules.prerender && !rules.redirect return !!rules.prerender && !rules.redirect
}) })
} }

View File

@ -4,7 +4,7 @@ import { getRouteRules } from '../composables/manifest'
export default defineNuxtRouteMiddleware(async (to) => { export default defineNuxtRouteMiddleware(async (to) => {
if (import.meta.server || import.meta.test) { return } if (import.meta.server || import.meta.test) { return }
const rules = await getRouteRules(to.path) const rules = await getRouteRules({ path: to.path })
if (rules.redirect) { if (rules.redirect) {
if (hasProtocol(rules.redirect, { acceptRelative: true })) { if (hasProtocol(rules.redirect, { acceptRelative: true })) {
window.location.href = rules.redirect window.location.href = rules.redirect

View File

@ -248,7 +248,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
const middlewareEntries = new Set<RouteGuard>([...globalMiddleware, ...nuxtApp._middleware.global]) const middlewareEntries = new Set<RouteGuard>([...globalMiddleware, ...nuxtApp._middleware.global])
if (isAppManifestEnabled) { if (isAppManifestEnabled) {
const routeRules = await nuxtApp.runWithContext(() => getRouteRules(to.path)) const routeRules = await nuxtApp.runWithContext(() => getRouteRules({ path: to.path }))
if (routeRules.appMiddleware) { if (routeRules.appMiddleware) {
for (const key in routeRules.appMiddleware) { for (const key in routeRules.appMiddleware) {

View File

@ -199,7 +199,7 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
} }
if (isAppManifestEnabled) { if (isAppManifestEnabled) {
const routeRules = await nuxtApp.runWithContext(() => getRouteRules(to.path)) const routeRules = await nuxtApp.runWithContext(() => getRouteRules({ path: to.path }))
if (routeRules.appMiddleware) { if (routeRules.appMiddleware) {
for (const key in routeRules.appMiddleware) { for (const key in routeRules.appMiddleware) {

View File

@ -2,6 +2,9 @@ import { describe, expectTypeOf, it } from 'vitest'
import type { Ref, SlotsType } from 'vue' import type { Ref, SlotsType } from 'vue'
import type { FetchError } from 'ofetch' import type { FetchError } from 'ofetch'
import type { NavigationFailure, RouteLocationNormalized, RouteLocationRaw, Router, useRouter as vueUseRouter } from 'vue-router' import type { NavigationFailure, RouteLocationNormalized, RouteLocationRaw, Router, useRouter as vueUseRouter } from 'vue-router'
import type { H3Event } from 'h3'
import { getRouteRules as getNitroRouteRules } from 'nitro/runtime'
import type { NitroRouteRules } from 'nitro/types'
import type { AppConfig, RuntimeValue, UpperSnakeCase } from 'nuxt/schema' import type { AppConfig, RuntimeValue, UpperSnakeCase } from 'nuxt/schema'
import { defineNuxtModule } from 'nuxt/kit' import { defineNuxtModule } from 'nuxt/kit'
@ -110,6 +113,21 @@ describe('API routes', () => {
}) })
}) })
describe('nitro compatible APIs', () => {
it('getRouteRules', async () => {
const a = await getRouteRules('/test')
const b = await getRouteRules({} as H3Event)
const c = getNitroRouteRules({} as H3Event)
expectTypeOf(b).toEqualTypeOf(c)
expectTypeOf(c).toEqualTypeOf<NitroRouteRules>()
expectTypeOf(a).toEqualTypeOf<Record<string, any>>()
})
it('useRuntimeConfig', () => {
useRuntimeConfig({} as H3Event)
})
})
describe('aliases', () => { describe('aliases', () => {
it('allows importing from path aliases', () => { it('allows importing from path aliases', () => {
expectTypeOf(useRouter).toEqualTypeOf<typeof vueUseRouter>() expectTypeOf(useRouter).toEqualTypeOf<typeof vueUseRouter>()

View File

@ -557,8 +557,8 @@ describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', (
`) `)
}) })
it('getRouteRules', async () => { it('getRouteRules', async () => {
expect(await getRouteRules('/')).toMatchInlineSnapshot('{}') expect(await getRouteRules({ path: '/' })).toMatchInlineSnapshot('{}')
expect(await getRouteRules('/pre')).toMatchInlineSnapshot(` expect(await getRouteRules({ path: '/pre' })).toMatchInlineSnapshot(`
{ {
"prerender": true, "prerender": true,
} }