@@ -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,8 +26,24 @@ 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
- constructor ( public readonly path : string , public readonly className : string = null ) { }
42
+ constructor ( public readonly path : string , public readonly className : string = null ) {
43
+ if ( arguments . length == 1 ) {
44
+ [ this . path , this . className ] = path . split ( '#' ) ;
45
+ }
46
+ }
30
47
31
48
toString ( ) {
32
49
return `${ this . path } #${ this . className } ` ;
@@ -57,6 +74,7 @@ export class AotPlugin {
57
74
58
75
private _typeCheck : boolean = true ;
59
76
private _basePath : string ;
77
+ private _genDir : string ;
60
78
61
79
62
80
constructor ( options : AotPluginOptions ) {
@@ -68,7 +86,7 @@ export class AotPlugin {
68
86
get compilerOptions ( ) { return this . _compilerOptions ; }
69
87
get done ( ) { return this . _donePromise ; }
70
88
get entryModule ( ) { return this . _entryModule ; }
71
- get genDir ( ) { return this . _basePath ; }
89
+ get genDir ( ) { return this . _genDir ; }
72
90
get program ( ) { return this . _program ; }
73
91
get typeCheck ( ) { return this . _typeCheck ; }
74
92
@@ -113,6 +131,7 @@ export class AotPlugin {
113
131
genDir
114
132
} ) ;
115
133
this . _basePath = basePath ;
134
+ this . _genDir = genDir ;
116
135
117
136
if ( options . hasOwnProperty ( 'typeChecking' ) ) {
118
137
this . _typeCheck = options . typeChecking ;
@@ -168,9 +187,9 @@ export class AotPlugin {
168
187
169
188
// Virtual file system.
170
189
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 ) {
190
+ if ( request . request . match ( / \. t s $ / ) ) {
191
+ this . done . then ( ( ) => cb ( ) ) ;
192
+ } else {
174
193
cb ( ) ;
175
194
}
176
195
} ) ;
@@ -227,49 +246,85 @@ export class AotPlugin {
227
246
throw new Error ( message ) ;
228
247
}
229
248
} )
249
+ . then ( ( ) => {
250
+ // Populate the file system cache with the virtual module.
251
+ this . _compilerHost . populateWebpackResolver ( this . _compiler . resolvers . normal ) ;
252
+ } )
230
253
. then ( ( ) => {
231
254
// 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
- } , { } ) ;
255
+ this . _lazyRoutes = { } ;
256
+ const allLazyRoutes = this . _processNgModule ( this . _entryModule , null ) ;
257
+ Object . keys ( allLazyRoutes )
258
+ . forEach ( k => {
259
+ const lazyRoute = allLazyRoutes [ k ] ;
260
+ this . _lazyRoutes [ k + '.ngfactory' ] = lazyRoute . moduleAbsolutePath + '.ngfactory.ts' ;
261
+ } ) ;
240
262
} )
241
- . then ( ( ) => cb ( ) , ( err : any ) => cb ( err ) ) ;
263
+ . then ( ( ) => cb ( ) , ( err : any ) => { cb ( err ) ; } ) ;
242
264
}
243
265
244
- private _resolveModule ( module : ModuleRoute , containingFile : string ) {
266
+ private _resolveModulePath ( module : ModuleRoute , containingFile : string ) {
245
267
if ( module . path . startsWith ( '.' ) ) {
246
268
return path . join ( path . dirname ( containingFile ) , module . path ) ;
247
269
}
248
270
return module . path ;
249
271
}
250
272
251
- private _processNgModule ( module : ModuleRoute , containingFile : string | null ) : string [ ] {
273
+ private _processNgModule ( module : ModuleRoute , containingFile : string | null ) : LazyRouteMap {
252
274
const modulePath = containingFile ? module . path : ( './' + path . basename ( module . path ) ) ;
253
275
if ( containingFile === null ) {
254
276
containingFile = module . path + '.ts' ;
255
277
}
278
+ const relativeModulePath = this . _resolveModulePath ( module , containingFile ) ;
256
279
257
- const resolvedModulePath = this . _resolveModule ( module , containingFile ) ;
258
280
const staticSymbol = this . _reflectorHost
259
281
. findDeclaration ( modulePath , module . className , containingFile ) ;
260
282
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
- } ) ;
283
+ const loadChildrenRoute : LazyRoute [ ] = this . extractLoadChildren ( entryNgModuleMetadata )
284
+ . map ( route => {
285
+ const mr = ModuleRoute . fromString ( route ) ;
286
+ const relativePath = this . _resolveModulePath ( mr , relativeModulePath ) ;
287
+ const absolutePath = path . join ( this . genDir , relativePath ) ;
288
+ return {
289
+ moduleRoute : mr ,
290
+ moduleRelativePath : relativePath ,
291
+ moduleAbsolutePath : absolutePath
292
+ } ;
293
+ } ) ;
294
+ const resultMap : LazyRouteMap = loadChildrenRoute
295
+ . reduce ( ( acc : LazyRouteMap , curr : LazyRoute ) => {
296
+ const key = curr . moduleRoute . path ;
297
+ if ( acc [ key ] ) {
298
+ if ( acc [ key ] . moduleAbsolutePath != curr . moduleAbsolutePath ) {
299
+ throw new Error ( `Duplicated path in loadChildren detected: "${ key } " is used in 2 ` +
300
+ 'loadChildren, but they point to different modules. Webpack cannot distinguish ' +
301
+ 'between the two based on context and would fail to load the proper one.' ) ;
302
+ }
303
+ } else {
304
+ acc [ key ] = curr ;
305
+ }
306
+ return acc ;
307
+ } , { } ) ;
265
308
266
309
// 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 ) ;
310
+ for ( const lazyRoute of loadChildrenRoute ) {
311
+ const mr = lazyRoute . moduleRoute ;
312
+ const children = this . _processNgModule ( mr , relativeModulePath ) ;
313
+ Object . keys ( children ) . forEach ( p => {
314
+ const child = children [ p ] ;
315
+ const key = child . moduleRoute . path ;
316
+ if ( resultMap [ key ] ) {
317
+ if ( resultMap [ key ] . moduleAbsolutePath != child . moduleAbsolutePath ) {
318
+ throw new Error ( `Duplicated path in loadChildren detected: "${ key } " is used in 2 ` +
319
+ 'loadChildren, but they point to different modules. Webpack cannot distinguish ' +
320
+ 'between the two based on context and would fail to load the proper one.' ) ;
321
+ }
322
+ } else {
323
+ resultMap [ key ] = child ;
324
+ }
325
+ } ) ;
271
326
}
272
- return result ;
327
+ return resultMap ;
273
328
}
274
329
275
330
private getNgModuleMetadata ( staticSymbol : ngCompiler . StaticSymbol ) {
@@ -281,10 +336,23 @@ export class AotPlugin {
281
336
}
282
337
283
338
private extractLoadChildren ( ngModuleDecorator : any ) : any [ ] {
284
- const routes = ngModuleDecorator . imports . reduce ( ( mem : any [ ] , m : any ) => {
339
+ const routes = ( ngModuleDecorator . imports || [ ] ) . reduce ( ( mem : any [ ] , m : any ) => {
285
340
return mem . concat ( this . collectRoutes ( m . providers ) ) ;
286
341
} , this . collectRoutes ( ngModuleDecorator . providers ) ) ;
287
- return this . collectLoadChildren ( routes ) ;
342
+ return this . collectLoadChildren ( routes )
343
+ . concat ( ( ngModuleDecorator . imports || [ ] )
344
+ // Also recursively extractLoadChildren of modules we import.
345
+ . map ( ( staticSymbol : any ) => {
346
+ if ( staticSymbol instanceof StaticSymbol ) {
347
+ const entryNgModuleMetadata = this . getNgModuleMetadata ( staticSymbol ) ;
348
+ return this . extractLoadChildren ( entryNgModuleMetadata ) ;
349
+ } else {
350
+ return [ ] ;
351
+ }
352
+ } )
353
+ // Poor man's flat map.
354
+ . reduce ( ( acc : any [ ] , i : any ) => acc . concat ( i ) , [ ] ) )
355
+ . filter ( x => ! ! x ) ;
288
356
}
289
357
290
358
private collectRoutes ( providers : any [ ] ) : any [ ] {
0 commit comments