@@ -11,6 +11,7 @@ import {WebpackResourceLoader} from './resource_loader';
11
11
import { createResolveDependenciesFromContextMap } from './utils' ;
12
12
import { WebpackCompilerHost } from './compiler_host' ;
13
13
import { resolveEntryModuleFromMain } from './entry_resolver' ;
14
+ import { StaticSymbol } from '@angular/compiler-cli' ;
14
15
15
16
16
17
/**
@@ -25,6 +26,18 @@ export interface AotPluginOptions {
25
26
}
26
27
27
28
29
+ export interface LazyRoute {
30
+ moduleRoute : ModuleRoute ;
31
+ moduleRelativePath : string ;
32
+ moduleAbsolutePath : string ;
33
+ }
34
+
35
+
36
+ export interface LazyRouteMap {
37
+ [ path : string ] : LazyRoute ;
38
+ }
39
+
40
+
28
41
export class ModuleRoute {
29
42
constructor ( public readonly path : string , public readonly className : string = null ) { }
30
43
@@ -57,6 +70,7 @@ export class AotPlugin {
57
70
58
71
private _typeCheck : boolean = true ;
59
72
private _basePath : string ;
73
+ private _genDir : string ;
60
74
61
75
62
76
constructor ( options : AotPluginOptions ) {
@@ -68,7 +82,7 @@ export class AotPlugin {
68
82
get compilerOptions ( ) { return this . _compilerOptions ; }
69
83
get done ( ) { return this . _donePromise ; }
70
84
get entryModule ( ) { return this . _entryModule ; }
71
- get genDir ( ) { return this . _basePath ; }
85
+ get genDir ( ) { return this . _genDir ; }
72
86
get program ( ) { return this . _program ; }
73
87
get typeCheck ( ) { return this . _typeCheck ; }
74
88
@@ -113,6 +127,7 @@ export class AotPlugin {
113
127
genDir
114
128
} ) ;
115
129
this . _basePath = basePath ;
130
+ this . _genDir = genDir ;
116
131
117
132
if ( options . hasOwnProperty ( 'typeChecking' ) ) {
118
133
this . _typeCheck = options . typeChecking ;
@@ -168,9 +183,9 @@ export class AotPlugin {
168
183
169
184
// Virtual file system.
170
185
compiler . resolvers . normal . plugin ( 'resolve' , ( request : any , cb ?: ( ) => void ) => {
171
- // Populate the file system cache with the virtual module.
172
- this . _compilerHost . populateWebpackResolver ( compiler . resolvers . normal ) ;
173
- if ( cb ) {
186
+ if ( request . request . match ( / \. t s $ / ) ) {
187
+ this . done . then ( ( ) => cb ( ) ) ;
188
+ } else {
174
189
cb ( ) ;
175
190
}
176
191
} ) ;
@@ -227,49 +242,85 @@ export class AotPlugin {
227
242
throw new Error ( message ) ;
228
243
}
229
244
} )
245
+ . then ( ( ) => {
246
+ // Populate the file system cache with the virtual module.
247
+ this . _compilerHost . populateWebpackResolver ( this . _compiler . resolvers . normal ) ;
248
+ } )
230
249
. then ( ( ) => {
231
250
// Process the lazy routes
232
- this . _lazyRoutes =
233
- this . _processNgModule ( this . _entryModule , null )
234
- . map ( module => ModuleRoute . fromString ( module ) )
235
- . reduce ( ( lazyRoutes : any , module : ModuleRoute ) => {
236
- lazyRoutes [ `${ module . path } .ngfactory` ] = path . join (
237
- this . genDir , module . path + '.ngfactory.ts' ) ;
238
- return lazyRoutes ;
239
- } , { } ) ;
251
+ this . _lazyRoutes = { } ;
252
+ const allLazyRoutes = this . _processNgModule ( this . _entryModule , null ) ;
253
+ Object . keys ( allLazyRoutes )
254
+ . forEach ( k => {
255
+ const lazyRoute = allLazyRoutes [ k ] ;
256
+ this . _lazyRoutes [ k + '.ngfactory' ] = lazyRoute . moduleAbsolutePath + '.ngfactory.ts' ;
257
+ } ) ;
240
258
} )
241
- . then ( ( ) => cb ( ) , ( err : any ) => cb ( err ) ) ;
259
+ . then ( ( ) => cb ( ) , ( err : any ) => { cb ( err ) ; } ) ;
242
260
}
243
261
244
- private _resolveModule ( module : ModuleRoute , containingFile : string ) {
262
+ private _resolveModulePath ( module : ModuleRoute , containingFile : string ) {
245
263
if ( module . path . startsWith ( '.' ) ) {
246
264
return path . join ( path . dirname ( containingFile ) , module . path ) ;
247
265
}
248
266
return module . path ;
249
267
}
250
268
251
- private _processNgModule ( module : ModuleRoute , containingFile : string | null ) : string [ ] {
269
+ private _processNgModule ( module : ModuleRoute , containingFile : string | null ) : LazyRouteMap {
252
270
const modulePath = containingFile ? module . path : ( './' + path . basename ( module . path ) ) ;
253
271
if ( containingFile === null ) {
254
272
containingFile = module . path + '.ts' ;
255
273
}
274
+ const relativeModulePath = this . _resolveModulePath ( module , containingFile ) ;
256
275
257
- const resolvedModulePath = this . _resolveModule ( module , containingFile ) ;
258
276
const staticSymbol = this . _reflectorHost
259
277
. findDeclaration ( modulePath , module . className , containingFile ) ;
260
278
const entryNgModuleMetadata = this . getNgModuleMetadata ( staticSymbol ) ;
261
- const loadChildren = this . extractLoadChildren ( entryNgModuleMetadata ) ;
262
- const result = loadChildren . map ( route => {
263
- return this . _resolveModule ( new ModuleRoute ( route ) , resolvedModulePath ) ;
264
- } ) ;
279
+ const loadChildrenRoute : LazyRoute [ ] = this . extractLoadChildren ( entryNgModuleMetadata )
280
+ . map ( route => {
281
+ const mr = ModuleRoute . fromString ( route ) ;
282
+ const relativePath = this . _resolveModulePath ( mr , relativeModulePath ) ;
283
+ const absolutePath = path . join ( this . genDir , relativePath ) ;
284
+ return {
285
+ moduleRoute : mr ,
286
+ moduleRelativePath : relativePath ,
287
+ moduleAbsolutePath : absolutePath
288
+ } ;
289
+ } ) ;
290
+ const resultMap : LazyRouteMap = loadChildrenRoute
291
+ . reduce ( ( acc : LazyRouteMap , curr : LazyRoute ) => {
292
+ const key = curr . moduleRoute . path ;
293
+ if ( acc [ key ] ) {
294
+ if ( acc [ key ] . moduleAbsolutePath != curr . moduleAbsolutePath ) {
295
+ throw new Error ( `Duplicated path in loadChildren detected: "${ key } " is used in 2 ` +
296
+ 'loadChildren, but they point to different modules. Webpack cannot distinguish ' +
297
+ 'between the two based on context and would fail to load the proper one.' ) ;
298
+ }
299
+ } else {
300
+ acc [ key ] = curr ;
301
+ }
302
+ return acc ;
303
+ } , { } ) ;
265
304
266
305
// Also concatenate every child of child modules.
267
- for ( const route of loadChildren ) {
268
- const childModule = ModuleRoute . fromString ( route ) ;
269
- const children = this . _processNgModule ( childModule , resolvedModulePath + '.ts' ) ;
270
- result . push ( ...children ) ;
306
+ for ( const lazyRoute of loadChildrenRoute ) {
307
+ const mr = lazyRoute . moduleRoute ;
308
+ const children = this . _processNgModule ( mr , relativeModulePath ) ;
309
+ Object . keys ( children ) . forEach ( p => {
310
+ const child = children [ p ] ;
311
+ const key = child . moduleRoute . path ;
312
+ if ( resultMap [ key ] ) {
313
+ if ( resultMap [ key ] . moduleAbsolutePath != child . moduleAbsolutePath ) {
314
+ throw new Error ( `Duplicated path in loadChildren detected: "${ key } " is used in 2 ` +
315
+ 'loadChildren, but they point to different modules. Webpack cannot distinguish ' +
316
+ 'between the two based on context and would fail to load the proper one.' ) ;
317
+ }
318
+ } else {
319
+ resultMap [ key ] = child ;
320
+ }
321
+ } ) ;
271
322
}
272
- return result ;
323
+ return resultMap ;
273
324
}
274
325
275
326
private getNgModuleMetadata ( staticSymbol : ngCompiler . StaticSymbol ) {
@@ -281,10 +332,23 @@ export class AotPlugin {
281
332
}
282
333
283
334
private extractLoadChildren ( ngModuleDecorator : any ) : any [ ] {
284
- const routes = ngModuleDecorator . imports . reduce ( ( mem : any [ ] , m : any ) => {
335
+ const routes = ( ngModuleDecorator . imports || [ ] ) . reduce ( ( mem : any [ ] , m : any ) => {
285
336
return mem . concat ( this . collectRoutes ( m . providers ) ) ;
286
337
} , this . collectRoutes ( ngModuleDecorator . providers ) ) ;
287
- return this . collectLoadChildren ( routes ) ;
338
+ return this . collectLoadChildren ( routes )
339
+ . concat ( ( ngModuleDecorator . imports || [ ] )
340
+ // Also recursively extractLoadChildren of modules we import.
341
+ . map ( ( staticSymbol : any ) => {
342
+ if ( staticSymbol instanceof StaticSymbol ) {
343
+ const entryNgModuleMetadata = this . getNgModuleMetadata ( staticSymbol ) ;
344
+ return this . extractLoadChildren ( entryNgModuleMetadata ) ;
345
+ } else {
346
+ return [ ] ;
347
+ }
348
+ } )
349
+ // Poor man's flat map.
350
+ . reduce ( ( acc : any [ ] , i : any ) => acc . concat ( i ) , [ ] ) )
351
+ . filter ( x => ! ! x ) ;
288
352
}
289
353
290
354
private collectRoutes ( providers : any [ ] ) : any [ ] {
0 commit comments