@@ -10,8 +10,6 @@ interface GlobalConfig {
10
10
'@embroider/core' ?: { active : boolean } ;
11
11
}
12
12
13
- type EngineInfoByRoute = Record < string , { name : string } > ;
14
-
15
13
let Router : typeof EmberRouter ;
16
14
17
15
interface GetRoute {
@@ -20,25 +18,40 @@ interface GetRoute {
20
18
}
21
19
22
20
interface Internals {
21
+ _engineInfoByRoute : Record < string , { name : string } > ;
23
22
_routerMicrolib : {
24
23
getRoute : GetRoute ;
25
24
} ;
26
25
}
27
26
27
+ interface EmbroiderBundle {
28
+ names : string [ ] ;
29
+ loaded ?: true ;
30
+ load : ( ) => Promise < void > ;
31
+ }
32
+
28
33
if ( macroCondition ( getGlobalConfig < GlobalConfig > ( ) [ '@embroider/core' ] ?. active ?? false ) ) {
29
34
const waiter = buildWaiter ( '@embroider/router:lazy-route-waiter' ) ;
30
35
31
36
function embroiderBundles ( ) : {
32
- _embroiderEngineBundles_ ?: { names : string [ ] ; loaded ?: true ; load : ( ) => Promise < void > } [ ] ;
33
- _embroiderRouteBundles_ ?: { names : string [ ] ; loaded ?: true ; load : ( ) => Promise < void > } [ ] ;
37
+ _embroiderEngineBundles_ ?: EmbroiderBundle [ ] ;
38
+ _embroiderRouteBundles_ ?: EmbroiderBundle [ ] ;
34
39
} {
35
40
return window as ReturnType < typeof embroiderBundles > ;
36
41
}
37
42
38
43
class EmbroiderRouter extends EmberRouter {
39
- private lazyBundle ( routeName : string ) {
40
- let engineInfoByRoute = ( this as unknown as { _engineInfoByRoute : EngineInfoByRoute } ) . _engineInfoByRoute ;
44
+ private seenByRoute = new Set < string > ( ) ;
41
45
46
+ private lazyRoute ( this : this & Internals , routeName : string ) : EmbroiderBundle | undefined {
47
+ let bundles = embroiderBundles ( ) ;
48
+ if ( bundles . _embroiderRouteBundles_ ) {
49
+ return bundles . _embroiderRouteBundles_ . find ( bundle => bundle . names . indexOf ( routeName ) !== - 1 ) ;
50
+ }
51
+ return undefined ;
52
+ }
53
+
54
+ private lazyEngine ( this : this & Internals , routeName : string ) : EmbroiderBundle | undefined {
42
55
// Here we map engine names to route names. We need to do this because
43
56
// engines can be specified with "as" such as:
44
57
//
@@ -48,28 +61,42 @@ if (macroCondition(getGlobalConfig<GlobalConfig>()['@embroider/core']?.active ??
48
61
// router is dynamic and the string could be defined as anything. Luckly, this._engineInfoByRoute contains
49
62
// mappings from routeName to the engines "original name" (which we know at build time).
50
63
let bundles = embroiderBundles ( ) ;
51
- let engine = engineInfoByRoute [ routeName ] ;
64
+ let engine = this . _engineInfoByRoute [ routeName ] ;
52
65
if ( engine && bundles . _embroiderEngineBundles_ ) {
53
66
let engineName = engine . name ;
54
67
return bundles . _embroiderEngineBundles_ . find ( bundle => bundle . names . indexOf ( engineName ) !== - 1 ) ;
55
68
}
69
+ return undefined ;
70
+ }
56
71
57
- if ( bundles . _embroiderRouteBundles_ ) {
58
- return bundles . _embroiderRouteBundles_ . find ( bundle => bundle . names . indexOf ( routeName ) !== - 1 ) ;
59
- }
60
-
61
- return false ;
72
+ private isEngine ( this : this & Internals , name : string ) : boolean {
73
+ return Boolean ( this . _engineInfoByRoute [ name ] ) ;
62
74
}
63
75
64
76
// This is necessary in order to prevent the premature loading of lazy routes
65
77
// when we are merely trying to render a link-to that points at them.
66
78
// Unfortunately the stock query parameter behavior pulls on routes just to
67
79
// check what their previous QP values were.
68
- _getQPMeta ( handlerInfo : { name : string } , ...rest : unknown [ ] ) {
69
- let bundle = this . lazyBundle ( handlerInfo . name ) ;
80
+ _getQPMeta ( this : this & Internals , handlerInfo : { name : string } , ...rest : unknown [ ] ) {
81
+ let bundle = this . lazyRoute ( handlerInfo . name ) ;
70
82
if ( bundle && ! bundle . loaded ) {
83
+ // unloaded split routes
84
+ return undefined ;
85
+ }
86
+
87
+ if ( this . isEngine ( handlerInfo . name ) && ! this . seenByRoute . has ( handlerInfo . name ) ) {
88
+ // unvisited engines, whether loaded or not, because the same bundle
89
+ // could by mounted multiple places and engines expect to only run the
90
+ // super._getQPMeta after they've been visited.
71
91
return undefined ;
72
92
}
93
+
94
+ bundle = this . lazyEngine ( handlerInfo . name ) ;
95
+ if ( bundle && ! bundle . loaded ) {
96
+ // unloaded lazy engines
97
+ return undefined ;
98
+ }
99
+
73
100
// @ts -expect-error extending private method
74
101
return super . _getQPMeta ( handlerInfo , ...rest ) ;
75
102
}
@@ -86,9 +113,10 @@ if (macroCondition(getGlobalConfig<GlobalConfig>()['@embroider/core']?.active ??
86
113
return isSetup ;
87
114
}
88
115
89
- private _handlerResolver ( original : ( name : string ) => unknown ) {
116
+ private _handlerResolver ( this : this & Internals , original : ( name : string ) => unknown ) {
90
117
let handler = ( ( name : string ) => {
91
- const bundle = this . lazyBundle ( name ) ;
118
+ const bundle = this . lazyRoute ( name ) ?? this . lazyEngine ( name ) ;
119
+ this . seenByRoute . add ( name ) ;
92
120
if ( ! bundle || bundle . loaded ) {
93
121
return original ( name ) ;
94
122
}
0 commit comments