From: Eduardo San Martin Morote Date: Mon, 20 Apr 2020 21:28:00 +0000 (+0200) Subject: fix(guards): preserve navigation options when redirecting X-Git-Tag: v4.0.0-alpha.8~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9effd816c51b58cb1103d878799aed6992f78454;p=thirdparty%2Fvuejs%2Frouter.git fix(guards): preserve navigation options when redirecting --- diff --git a/__tests__/router.spec.ts b/__tests__/router.spec.ts index c3c41b78..67375a35 100644 --- a/__tests__/router.spec.ts +++ b/__tests__/router.spec.ts @@ -119,6 +119,25 @@ describe('Router', () => { ) }) + it('replaces if a guard redirects', async () => { + const history = createMemoryHistory() + const { router } = await newRouter({ history }) + // move somewhere else + await router.push('/search') + jest.spyOn(history, 'replace') + await router.replace('/home-before') + expect(history.replace).toHaveBeenCalledTimes(1) + expect(history.replace).toHaveBeenCalledWith( + expect.objectContaining({ + fullPath: '/', + path: '/', + query: {}, + hash: '', + }), + undefined + ) + }) + it('allows to customize parseQuery', async () => { const parseQuery = jest.fn() const { router } = await newRouter({ parseQuery }) diff --git a/src/components/View.ts b/src/components/View.ts index 9c2134e4..addf04ea 100644 --- a/src/components/View.ts +++ b/src/components/View.ts @@ -67,10 +67,11 @@ export const View = (defineComponent({ // we nee the value at the time we render because when we unmount, we // navigated to a different location so the value is different const currentMatched = matchedRoute.value + const currentName = props.name function onVnodeUnmounted() { if (currentMatched) { // remove the instance reference to prevent leak - currentMatched.instances[props.name] = null + currentMatched.instances[currentName] = null } } diff --git a/src/index.ts b/src/index.ts index 8098ba7a..38b92cc3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ export { RouteRecord, RouteRecordNormalized } from './matcher/types' export { RouteLocationRaw, + RouteLocation, RouteLocationNormalized, RouteLocationNormalizedLoaded, START_LOCATION_NORMALIZED as START_LOCATION, diff --git a/src/router.ts b/src/router.ts index a4c60925..269a4c62 100644 --- a/src/router.ts +++ b/src/router.ts @@ -13,6 +13,7 @@ import { RouteRecordName, isRouteName, NavigationGuardWithThis, + RouteLocationOptions, } from './types' import { RouterHistory, HistoryState } from './history/common' import { @@ -249,9 +250,10 @@ export function createRouter({ ): Promise { const targetLocation: RouteLocation = (pendingLocation = resolve(to)) const from = currentRoute.value - const data: HistoryState | undefined = (to as any).state - const force: boolean | undefined = (to as any).force - const replace: boolean | undefined = (to as any).replace === true + const data: HistoryState | undefined = (to as RouteLocationOptions).state + const force: boolean | undefined = (to as RouteLocationOptions).force + // to could be a string where `replace` is a function + const replace = (to as RouteLocationOptions).replace === true if (!force && isSameRouteLocation(from, targetLocation)) return @@ -294,7 +296,13 @@ export function createRouter({ } else if (error.type === ErrorTypes.NAVIGATION_GUARD_REDIRECT) { // preserve the original redirectedFrom if any return pushWithRedirect( - (error as NavigationRedirectError).to, + // keep options + { + ...locationAsObject((error as NavigationRedirectError).to), + state: data, + force, + replace, + }, redirectedFrom || toLocation ) } else { @@ -503,6 +511,7 @@ export function createRouter({ return pushWithRedirect( (error as NavigationRedirectError).to, toLocation + // TODO: in dev show warning, in prod noop, same as initial navigation ).catch(() => {}) } else { // TODO: test on different browsers ensure consistent behavior diff --git a/src/types/index.ts b/src/types/index.ts index 0b1a6d2b..f2b7631c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,6 +1,6 @@ import { LocationQuery, LocationQueryRaw } from '../utils/query' import { PathParserOptions } from '../matcher/path-parser-ranker' -import { markRaw, Ref, ComputedRef, Component } from 'vue' +import { markRaw, Ref, ComputedRef, ComponentOptions } from 'vue' import { RouteRecord, RouteRecordNormalized } from '../matcher/types' import { HistoryState } from '../history/common' @@ -128,7 +128,7 @@ export interface RouteLocationNormalized extends _RouteLocationBase { matched: RouteRecordNormalized[] // non-enumerable } -export type RouteComponent = Component +export type RouteComponent = ComponentOptions export type RawRouteComponent = RouteComponent | Lazy export type RouteRecordName = string | symbol