@@ -545,24 +545,13 @@ export function createRouter(options: RouterOptions): Router {
545
545
return push ( assign ( locationAsObject ( to ) , { replace : true } ) )
546
546
}
547
547
548
- function pushWithRedirect (
549
- to : RouteLocationRaw | RouteLocation ,
550
- redirectedFrom ?: RouteLocation
551
- ) : Promise < NavigationFailure | void | undefined > {
552
- const targetLocation : RouteLocation = ( pendingLocation = resolve ( to ) )
553
- const from = currentRoute . value
554
- const data : HistoryState | undefined = ( to as RouteLocationOptions ) . state
555
- const force : boolean | undefined = ( to as RouteLocationOptions ) . force
556
- // to could be a string where `replace` is a function
557
- const replace = ( to as RouteLocationOptions ) . replace === true
558
-
559
- const lastMatched =
560
- targetLocation . matched [ targetLocation . matched . length - 1 ]
548
+ function handleRedirectRecord ( to : RouteLocation ) : RouteLocationRaw | void {
549
+ const lastMatched = to . matched [ to . matched . length - 1 ]
561
550
if ( lastMatched && lastMatched . redirect ) {
562
551
const { redirect } = lastMatched
563
552
// transform it into an object to pass the original RouteLocaleOptions
564
553
let newTargetLocation = locationAsObject (
565
- typeof redirect === 'function' ? redirect ( targetLocation ) : redirect
554
+ typeof redirect === 'function' ? redirect ( to ) : redirect
566
555
)
567
556
568
557
if (
@@ -576,29 +565,42 @@ export function createRouter(options: RouterOptions): Router {
576
565
null ,
577
566
2
578
567
) } \n when navigating to "${
579
- targetLocation . fullPath
568
+ to . fullPath
580
569
} ". A redirect must contain a name or path. This will break in production.`
581
570
)
582
- return Promise . reject ( new Error ( 'Invalid redirect' ) )
571
+ throw new Error ( 'Invalid redirect' )
583
572
}
573
+
574
+ return assign (
575
+ {
576
+ query : to . query ,
577
+ hash : to . hash ,
578
+ params : to . params ,
579
+ } ,
580
+ newTargetLocation
581
+ )
582
+ }
583
+ }
584
+
585
+ function pushWithRedirect (
586
+ to : RouteLocationRaw | RouteLocation ,
587
+ redirectedFrom ?: RouteLocation
588
+ ) : Promise < NavigationFailure | void | undefined > {
589
+ const targetLocation : RouteLocation = ( pendingLocation = resolve ( to ) )
590
+ const from = currentRoute . value
591
+ const data : HistoryState | undefined = ( to as RouteLocationOptions ) . state
592
+ const force : boolean | undefined = ( to as RouteLocationOptions ) . force
593
+ // to could be a string where `replace` is a function
594
+ const replace = ( to as RouteLocationOptions ) . replace === true
595
+
596
+ const shouldRedirect = handleRedirectRecord ( targetLocation )
597
+
598
+ if ( shouldRedirect )
584
599
return pushWithRedirect (
585
- assign (
586
- {
587
- query : targetLocation . query ,
588
- hash : targetLocation . hash ,
589
- params : targetLocation . params ,
590
- } ,
591
- newTargetLocation ,
592
- {
593
- state : data ,
594
- force,
595
- replace,
596
- }
597
- ) ,
600
+ assign ( shouldRedirect , { state : data , force, replace } ) ,
598
601
// keep original redirectedFrom if it exists
599
602
redirectedFrom || targetLocation
600
603
)
601
- }
602
604
603
605
// if it was a redirect we already called `pushWithRedirect` above
604
606
const toLocation = targetLocation as RouteLocationNormalized
@@ -616,7 +618,7 @@ export function createRouter(options: RouterOptions): Router {
616
618
from ,
617
619
from ,
618
620
// this is a push, the only way for it to be triggered from a
619
- // history.listen is with a redirect, which makes it become a pus
621
+ // history.listen is with a redirect, which makes it become a push
620
622
true ,
621
623
// This cannot be the first navigation because the initial ___location
622
624
// cannot be manually navigated to
@@ -625,20 +627,12 @@ export function createRouter(options: RouterOptions): Router {
625
627
}
626
628
627
629
return ( failure ? Promise . resolve ( failure ) : navigate ( toLocation , from ) )
628
- . catch ( ( error : NavigationFailure | NavigationRedirectError ) => {
629
- if (
630
- isNavigationFailure (
631
- error ,
632
- ErrorTypes . NAVIGATION_ABORTED |
633
- ErrorTypes . NAVIGATION_CANCELLED |
634
- ErrorTypes . NAVIGATION_GUARD_REDIRECT
635
- )
636
- ) {
637
- return error
638
- }
639
- // unknown error, rejects
640
- return triggerError ( error )
641
- } )
630
+ . catch ( ( error : NavigationFailure | NavigationRedirectError ) =>
631
+ isNavigationFailure ( error )
632
+ ? error
633
+ : // reject any unknown error
634
+ triggerError ( error )
635
+ )
642
636
. then ( ( failure : NavigationFailure | NavigationRedirectError | void ) => {
643
637
if ( failure ) {
644
638
if (
@@ -896,7 +890,19 @@ export function createRouter(options: RouterOptions): Router {
896
890
function setupListeners ( ) {
897
891
removeHistoryListener = routerHistory . listen ( ( to , _from , info ) => {
898
892
// cannot be a redirect route because it was in history
899
- const toLocation = resolve ( to ) as RouteLocationNormalized
893
+ let toLocation = resolve ( to ) as RouteLocationNormalized
894
+
895
+ // due to dynamic routing, and to hash history with manual navigation
896
+ // (manually changing the url or calling history.hash = '#/somewhere'),
897
+ // there could be a redirect record in history
898
+ const shouldRedirect = handleRedirectRecord ( toLocation )
899
+ if ( shouldRedirect ) {
900
+ pushWithRedirect (
901
+ assign ( shouldRedirect , { replace : true } ) ,
902
+ toLocation
903
+ ) . catch ( noop )
904
+ return
905
+ }
900
906
901
907
pendingLocation = toLocation
902
908
const from = currentRoute . value
@@ -927,9 +933,10 @@ export function createRouter(options: RouterOptions): Router {
927
933
// the error is already handled by router.push we just want to avoid
928
934
// logging the error
929
935
pushWithRedirect (
936
+ // TODO: should we force replace: true
930
937
( error as NavigationRedirectError ) . to ,
931
938
toLocation
932
- // avoid an uncaught rejection
939
+ // avoid an uncaught rejection, let push call triggerError
933
940
) . catch ( noop )
934
941
// avoid the then branch
935
942
return Promise . reject ( )
0 commit comments