1
- /** @ng 2api @module core */ /** */
2
- import { NgModuleFactoryLoader , NgModuleRef , Injector , NgModuleFactory , Type , Compiler } from "@angular/core" ;
3
- import { Transition , LazyLoadResult , UIRouter , Resolvable , NATIVE_INJECTOR_TOKEN , isString } from "ui-router-core" ;
4
- import { RootModule , StatesModule , UIROUTER_ROOT_MODULE , UIROUTER_MODULE_TOKEN } from "./uiRouterNgModule" ;
5
- import { applyModuleConfig } from "./uiRouterConfig" ;
1
+ /** @ng 2api @module core */
2
+ /** */
3
+ import { NgModuleRef , Injector , NgModuleFactory , Type , Compiler , NgModuleFactoryLoader } from "@angular/core" ;
4
+ import { Transition , LazyLoadResult , UIRouter , Resolvable , NATIVE_INJECTOR_TOKEN , isString } from "ui-router-core" ;
5
+ import { RootModule , UIROUTER_ROOT_MODULE , UIROUTER_MODULE_TOKEN } from "../uiRouterNgModule" ;
6
+ import { applyModuleConfig } from "../uiRouterConfig" ;
6
7
8
+ /**
9
+ * A function that returns an NgModule, or a promise for an NgModule
10
+ *
11
+ * #### Example:
12
+ * ```js
13
+ * export function loadFooModule() {
14
+ * return System.import('../foo/foo.module').then(result => result.FooModule);
15
+ * }
16
+ * ```
17
+ */
7
18
export type ModuleTypeCallback = ( ) => Type < any > | Promise < Type < any > > ;
19
+ /**
20
+ * A string or a function which lazy loads a module
21
+ *
22
+ * If a string, should conform to the Angular Router `loadChildren` string.
23
+ * #### Example:
24
+ * ```
25
+ * var ngModuleToLoad = './foo/foo.module#FooModule'
26
+ * ```
27
+ *
28
+ * For functions, see: [[ModuleTypeCallback]]
29
+ */
8
30
export type NgModuleToLoad = string | ModuleTypeCallback ;
9
31
10
32
/**
11
33
* Returns a function which lazy loads a nested module
12
34
*
13
- * Use this function as a [[StateDeclaration.lazyLoad ]] property to lazy load an NgModule and its state .
35
+ * This is primarily used by the [[ng2LazyLoadBuilder ]] when processing [[Ng2StateDeclaration.loadChildren]] .
14
36
*
15
- * Example using `System.import()`:
37
+ * It could also be used manually as a [[StateDeclaration.lazyLoad]] property to lazy load an `NgModule` and its state(s).
38
+ *
39
+ * #### Example:
40
+ * Using `System.import()` and named export of `HomeModule`
16
41
* ```js
17
- * {
18
- * name: 'home',
42
+ * declare var System;
43
+ * var futureState = {
44
+ * name: 'home.**',
19
45
* url: '/home',
20
- * lazyLoad: loadNgModule(() => System.import('./home.module').then(result => result.HomeModule))
46
+ * lazyLoad: loadNgModule(() => System.import('./home/home .module').then(result => result.HomeModule))
21
47
* }
22
48
* ```
23
49
*
24
- * Example using `NgModuleFactoryLoader`:
50
+ * #### Example:
51
+ * Using a path (string) to the module
25
52
* ```js
26
- * {
27
- * name: 'home',
53
+ * var futureState = {
54
+ * name: 'home.** ',
28
55
* url: '/home',
29
- * lazyLoad: loadNgModule('./home.module')
56
+ * lazyLoad: loadNgModule('./home/home .module#HomeModule ')
30
57
* }
31
58
* ```
32
59
*
33
- * @param moduleToLoad
34
- * If a string, it should be the path to the NgModule code, which will then be loaded by the `NgModuleFactoryLoader`.
35
- * If a function, the function should load the NgModule code and return a reference to the `NgModule` class being loaded.
60
+ *
61
+ * @param moduleToLoad a path (string) to the NgModule to load.
62
+ * Or a function which loads the NgModule code which should
63
+ * return a reference to the `NgModule` class being loaded (or a `Promise` for it).
36
64
*
37
65
* @returns A function which takes a transition, which:
38
66
* - Gets the Injector (scoped properly for the destination state)
@@ -76,10 +104,13 @@ export function loadModuleFactory(moduleToLoad: NgModuleToLoad, ng2Injector: Inj
76
104
77
105
const compiler : Compiler = ng2Injector . get ( Compiler ) ;
78
106
const offlineMode = compiler instanceof Compiler ;
79
- const loadChildrenPromise = Promise . resolve ( moduleToLoad ( ) ) ;
107
+
108
+ const unwrapEsModuleDefault = x =>
109
+ x && x . __esModule && x [ 'default' ] ? x [ 'default' ] : x ;
80
110
const compileAsync = ( moduleType : Type < any > ) =>
81
111
compiler . compileModuleAsync ( moduleType ) ;
82
112
113
+ const loadChildrenPromise = Promise . resolve ( moduleToLoad ( ) ) . then ( unwrapEsModuleDefault ) ;
83
114
return offlineMode ? loadChildrenPromise : loadChildrenPromise . then ( compileAsync ) ;
84
115
}
85
116
@@ -101,23 +132,31 @@ export function applyNgModule(transition: Transition, ng2Module: NgModuleRef<any
101
132
let injector = ng2Module . injector ;
102
133
let parentInjector = < Injector > ng2Module . injector [ 'parent' ] ;
103
134
let uiRouter : UIRouter = injector . get ( UIRouter ) ;
135
+ let registry = uiRouter . stateRegistry ;
104
136
105
137
let originalName = transition . to ( ) . name ;
106
- let originalState = uiRouter . stateRegistry . get ( originalName ) ;
138
+ let originalState = registry . get ( originalName ) ;
139
+ // Check if it's a future state (ends with .**)
140
+ let isFuture = / ^ ( .* ) \. \* \* $ / . exec ( originalName ) ;
141
+ // Final name (without the .**)
142
+ let replacementName = isFuture && isFuture [ 1 ] ;
107
143
108
144
let newRootModules : RootModule [ ] = multiProviderParentChildDelta ( parentInjector , injector , UIROUTER_ROOT_MODULE ) ;
109
-
110
145
if ( newRootModules . length ) {
111
146
console . log ( newRootModules ) ;
112
147
throw new Error ( 'Lazy loaded modules should not contain a UIRouterModule.forRoot() module' ) ;
113
148
}
114
149
115
- let newModules : RootModule [ ] = multiProviderParentChildDelta ( parentInjector , injector , UIROUTER_MODULE_TOKEN ) ;
116
- newModules . forEach ( module => applyModuleConfig ( uiRouter , injector , module ) ) ;
150
+ let newChildModules : RootModule [ ] = multiProviderParentChildDelta ( parentInjector , injector , UIROUTER_MODULE_TOKEN ) ;
151
+ newChildModules . forEach ( module => applyModuleConfig ( uiRouter , injector , module ) ) ;
117
152
118
- let replacementState = uiRouter . stateRegistry . get ( originalName ) ;
119
- if ( replacementState === originalState ) {
120
- throw new Error ( `The Future State named '${ originalName } ' lazy loaded an NgModule. That NgModule should also have a UIRouterModule.forChild() state named '${ originalName } ' to replace the Future State, but it did not.` ) ;
153
+ let replacementState = registry . get ( replacementName ) ;
154
+ if ( ! replacementState || replacementState === originalState ) {
155
+ throw new Error ( `The Future State named '${ originalName } ' lazy loaded an NgModule. ` +
156
+ `The lazy loaded NgModule must have a state named '${ replacementName } ' ` +
157
+ `which replaces the (placeholder) '${ originalName } ' Future State. ` +
158
+ `Add a '${ replacementName } ' state to the lazy loaded NgModule ` +
159
+ `using UIRouterModule.forChild({ states: CHILD_STATES }).` ) ;
121
160
}
122
161
123
162
// Supply the newly loaded states with the Injector from the lazy loaded NgModule
0 commit comments