mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(router): add proper server side redirection to navigateTo (#3684)
Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
parent
93da7978fb
commit
99705f77c0
@ -4,6 +4,7 @@ import type { MetaInfo } from 'vue-meta'
|
||||
import type VueRouter from 'vue-router'
|
||||
import type { Location, Route } from 'vue-router'
|
||||
import type { RuntimeConfig } from '@nuxt/schema'
|
||||
import { sendRedirect } from 'h3'
|
||||
import defu from 'defu'
|
||||
import { useNuxtApp } from './app'
|
||||
|
||||
@ -172,12 +173,23 @@ const isProcessingMiddleware = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
export const navigateTo = (to: Route) => {
|
||||
export interface NavigateToOptions {
|
||||
replace?: boolean
|
||||
}
|
||||
|
||||
export const navigateTo = (to: Route, options: NavigateToOptions = {}) => {
|
||||
if (isProcessingMiddleware()) {
|
||||
return to
|
||||
}
|
||||
const router: VueRouter = process.server ? useRouter() : (window as any).$nuxt.$router
|
||||
return router.push(to)
|
||||
const router = useRouter()
|
||||
if (process.server && useNuxtApp().ssrContext) {
|
||||
// Server-side redirection using h3 res from ssrContext
|
||||
const res = useNuxtApp().ssrContext?.res
|
||||
const redirectLocation = router.resolve(to).route.fullPath
|
||||
return sendRedirect(res, redirectLocation)
|
||||
}
|
||||
// Client-side redirection using vue-router
|
||||
return options.replace ? router.replace(to) : router.push(to)
|
||||
}
|
||||
|
||||
/** This will abort navigation within a Nuxt route middleware handler. */
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw } from 'vue-router'
|
||||
import { sendRedirect } from 'h3'
|
||||
import { useNuxtApp } from '#app'
|
||||
|
||||
export const useRouter = () => {
|
||||
@ -45,12 +46,23 @@ const isProcessingMiddleware = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
export const navigateTo = (to: RouteLocationRaw) => {
|
||||
export interface NavigateToOptions {
|
||||
replace?: boolean
|
||||
}
|
||||
|
||||
export const navigateTo = (to: RouteLocationRaw, options: NavigateToOptions = {}) => {
|
||||
if (isProcessingMiddleware()) {
|
||||
return to
|
||||
}
|
||||
const router: Router = process.server ? useRouter() : (window as any).$nuxt.$router
|
||||
return router.push(to)
|
||||
const router = useRouter()
|
||||
if (process.server && useNuxtApp().ssrContext) {
|
||||
// Server-side redirection using h3 res from ssrContext
|
||||
const res = useNuxtApp().ssrContext?.res
|
||||
const redirectLocation = router.resolve(to).fullPath
|
||||
return sendRedirect(res, redirectLocation)
|
||||
}
|
||||
// Client-side redirection using vue-router
|
||||
return options.replace ? router.replace(to) : router.push(to)
|
||||
}
|
||||
|
||||
/** This will abort navigation within a Nuxt route middleware handler. */
|
||||
|
@ -94,6 +94,17 @@ describe('fixtures:basic', async () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('navigate', () => {
|
||||
it('should redirect to index with navigateTo', async () => {
|
||||
const html = await $fetch('/navigate-to/')
|
||||
|
||||
// Snapshot
|
||||
// expect(html).toMatchInlineSnapshot()
|
||||
|
||||
expect(html).toContain('Hello Nuxt 3!')
|
||||
})
|
||||
})
|
||||
|
||||
describe('middlewares', () => {
|
||||
it('should redirect to index with global middleware', async () => {
|
||||
const html = await $fetch('/redirect/')
|
||||
|
@ -8,7 +8,16 @@ describe('fixtures:bridge', async () => {
|
||||
server: true
|
||||
})
|
||||
|
||||
it('Render hello world', async () => {
|
||||
expect(await $fetch('/')).to.contain('Hello Vue 2!')
|
||||
describe('pages', () => {
|
||||
it('render hello world', async () => {
|
||||
expect(await $fetch('/')).to.contain('Hello Vue 2!')
|
||||
})
|
||||
})
|
||||
|
||||
describe('navigate', () => {
|
||||
it('should redirect to index with navigateTo', async () => {
|
||||
const html = await $fetch('/navigate-to/')
|
||||
expect(html).toContain('Hello Vue 2!')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
7
test/fixtures/basic/pages/navigate-to.vue
vendored
Normal file
7
test/fixtures/basic/pages/navigate-to.vue
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>You should not see me</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
navigateTo('/', { replace: true })
|
||||
</script>
|
2
test/fixtures/basic/types.ts
vendored
2
test/fixtures/basic/types.ts
vendored
@ -51,7 +51,7 @@ describe('middleware', () => {
|
||||
addRouteMiddleware('example', (to, from) => {
|
||||
expectTypeOf(to).toMatchTypeOf<RouteLocationNormalizedLoaded>()
|
||||
expectTypeOf(from).toMatchTypeOf<RouteLocationNormalizedLoaded>()
|
||||
expectTypeOf(navigateTo).toMatchTypeOf<(to: RouteLocationRaw) => RouteLocationRaw | Promise<void | NavigationFailure>>()
|
||||
expectTypeOf(navigateTo).toMatchTypeOf<(to: RouteLocationRaw) => RouteLocationRaw | Promise<void | unknown | NavigationFailure>>()
|
||||
navigateTo('/')
|
||||
abortNavigation()
|
||||
abortNavigation('error string')
|
||||
|
7
test/fixtures/bridge/pages/navigate-to.vue
vendored
Normal file
7
test/fixtures/bridge/pages/navigate-to.vue
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>You should not see me</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
navigateTo('/', { replace: true })
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user