@@ -15,6 +15,8 @@ export class History {
1515 cb: ( r : Route ) => void ;
1616 ready: boolean ;
1717 readyCbs: Array < Function > ;
18+ readyErrorCbs: Array < Function > ;
19+ errorCbs: Array < Function > ;
1820
1921 // implemented by sub-classes
2022 + go : ( n : number ) = > void ;
@@ -31,20 +33,29 @@ export class History {
3133 this . pending = null
3234 this . ready = false
3335 this . readyCbs = [ ]
36+ this . readyErrorCbs = [ ]
37+ this . errorCbs = [ ]
3438 }
3539
3640 listen ( cb : Function ) {
3741 this . cb = cb
3842 }
3943
40- onReady ( cb : Function ) {
44+ onReady ( cb : Function , errorCb : ? Function ) {
4145 if ( this . ready ) {
4246 cb ( )
4347 } else {
4448 this . readyCbs . push ( cb )
49+ if ( errorCb ) {
50+ this . readyErrorCbs . push ( errorCb )
51+ }
4552 }
4653 }
4754
55+ onError ( errorCb : Function ) {
56+ this . errorCbs . push ( errorCb )
57+ }
58+
4859 transitionTo ( location : RawLocation , onComplete ? : Function , onAbort ? : Function ) {
4960 const route = this . router . match ( location , this . current )
5061 this . confirmTransition ( route , ( ) => {
@@ -55,16 +66,27 @@ export class History {
5566 // fire ready cbs once
5667 if ( ! this . ready ) {
5768 this . ready = true
58- this . readyCbs . forEach ( cb => {
59- cb ( route )
60- } )
69+ this . readyCbs . forEach ( cb => { cb ( route ) } )
6170 }
62- } , onAbort )
71+ } , err => {
72+ if ( onAbort ) {
73+ onAbort ( err )
74+ }
75+ if ( err && ! this . ready ) {
76+ this . ready = true
77+ this . readyErrorCbs . forEach ( cb => { cb ( err ) } )
78+ }
79+ } )
6380 }
6481
6582 confirmTransition ( route : Route , onComplete : Function , onAbort ? : Function ) {
6683 const current = this . current
67- const abort = ( ) => { onAbort && onAbort ( ) }
84+ const abort = err => {
85+ if ( err instanceof Error ) {
86+ this . errorCbs . forEach ( cb => { cb ( err ) } )
87+ }
88+ onAbort && onAbort ( err )
89+ }
6890 if (
6991 isSameRoute ( route , current ) &&
7092 // in the case the route map has been dynamically appended to
@@ -98,20 +120,28 @@ export class History {
98120 if ( this . pending !== route ) {
99121 return abort ( )
100122 }
101- hook ( route , current , ( to : any ) => {
102- if ( to === false ) {
103- // next(false) -> abort navigation, ensure current URL
104- this . ensureURL ( true )
105- abort ( )
106- } else if ( typeof to === 'string' || typeof to === 'object' ) {
107- // next('/') or next({ path: '/' }) -> redirect
108- ( typeof to === 'object' && to . replace ) ? this . replace ( to ) : this . push ( to )
109- abort ( )
110- } else {
111- // confirm transition and pass on the value
112- next ( to )
113- }
114- } )
123+ try {
124+ hook ( route , current , ( to : any ) => {
125+ if ( to === false || to instanceof Error ) {
126+ // next(false) -> abort navigation, ensure current URL
127+ this . ensureURL ( true )
128+ abort ( to )
129+ } else if ( typeof to === 'string' || typeof to === 'object' ) {
130+ // next('/') or next({ path: '/' }) -> redirect
131+ abort ( )
132+ if ( typeof to === 'object' && to . replace ) {
133+ this . replace ( to )
134+ } else {
135+ this . push ( to )
136+ }
137+ } else {
138+ // confirm transition and pass on the value
139+ next ( to )
140+ }
141+ } )
142+ } catch ( e ) {
143+ abort ( e )
144+ }
115145 }
116146
117147 runQueue ( queue , iterator , ( ) => {
@@ -128,7 +158,7 @@ export class History {
128158 onComplete ( route )
129159 if ( this . router . app ) {
130160 this . router . app . $nextTick ( ( ) => {
131- postEnterCbs . forEach ( cb => cb ( ) )
161+ postEnterCbs . forEach ( cb => { cb ( ) } )
132162 } )
133163 }
134164 } )
@@ -279,7 +309,7 @@ function poll (
279309function resolveAsyncComponents ( matched : Array < RouteRecord > ) : Function {
280310 let _next
281311 let pending = 0
282- let rejected = false
312+ let error = null
283313
284314 flatMapComponents ( matched , ( def , _ , match , key ) => {
285315 // if it's a function and doesn't have cid attached,
@@ -299,23 +329,31 @@ function resolveAsyncComponents (matched: Array<RouteRecord>): Function {
299329 } )
300330
301331 const reject = once ( reason => {
302- warn ( false , `Failed to resolve async component ${ key } : ${ reason } ` )
303- if ( ! rejected ) {
304- rejected = true
305- if ( _next ) _next ( false )
332+ const msg = `Failed to resolve async component ${ key } : ${ reason } `
333+ process . env . NODE_ENV !== 'production' && warn ( false , msg )
334+ if ( ! error ) {
335+ error = reason instanceof Error
336+ ? reason
337+ : new Error ( msg )
338+ if ( _next ) _next ( error )
306339 }
307340 } )
308341
309- const res = def ( resolve , reject )
342+ let res
343+ try {
344+ res = def ( resolve , reject )
345+ } catch ( e ) {
346+ reject ( e )
347+ }
310348 if ( res && typeof res . then === 'function' ) {
311349 res . then ( resolve , reject )
312350 }
313351 }
314352 } )
315353
316354 return ( to , from , next ) = > {
317- if ( rejected ) {
318- next ( false )
355+ if ( error ) {
356+ next ( error )
319357 } else if ( pending <= 0 ) {
320358 next ( )
321359 } else {
0 commit comments