@@ -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 } ` ;
@@ -168,9 +185,9 @@ export class AotPlugin {
168
185
169
186
// Virtual file system.
170
187
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 ) {
188
+ if ( request . request . match ( / \. t s $ / ) ) {
189
+ this . done . then ( ( ) => cb ( ) ) ;
190
+ } else {
174
191
cb ( ) ;
175
192
}
176
193
} ) ;
@@ -227,49 +244,85 @@ export class AotPlugin {
227
244
throw new Error ( message ) ;
228
245
}
229
246
} )
247
+ . then ( ( ) => {
248
+ // Populate the file system cache with the virtual module.
249
+ this . _compilerHost . populateWebpackResolver ( this . _compiler . resolvers . normal ) ;
250
+ } )
230
251
. then ( ( ) => {
231
252
// 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
- } , { } ) ;
253
+ this . _lazyRoutes = { } ;
254
+ const allLazyRoutes = this . _processNgModule ( this . _entryModule , null ) ;
255
+ Object . keys ( allLazyRoutes )
256
+ . forEach ( k => {
257
+ const lazyRoute = allLazyRoutes [ k ] ;
258
+ this . _lazyRoutes [ k + '.ngfactory' ] = lazyRoute . moduleRelativePath + '.ngfactory.ts' ;
259
+ } ) ;
240
260
} )
241
- . then ( ( ) => cb ( ) , ( err : any ) => cb ( err ) ) ;
261
+ . then ( ( ) => cb ( ) , ( err : any ) => { cb ( err ) ; } ) ;
242
262
}
243
263
244
- private _resolveModule ( module : ModuleRoute , containingFile : string ) {
264
+ private _resolveModulePath ( module : ModuleRoute , containingFile : string ) {
245
265
if ( module . path . startsWith ( '.' ) ) {
246
266
return path . join ( path . dirname ( containingFile ) , module . path ) ;
247
267
}
248
268
return module . path ;
249
269
}
250
270
251
- private _processNgModule ( module : ModuleRoute , containingFile : string | null ) : string [ ] {
271
+ private _processNgModule ( module : ModuleRoute , containingFile : string | null ) : LazyRouteMap {
252
272
const modulePath = containingFile ? module . path : ( './' + path . basename ( module . path ) ) ;
253
273
if ( containingFile === null ) {
254
274
containingFile = module . path + '.ts' ;
255
275
}
276
+ const relativeModulePath = this . _resolveModulePath ( module , containingFile ) ;
256
277
257
- const resolvedModulePath = this . _resolveModule ( module , containingFile ) ;
258
278
const staticSymbol = this . _reflectorHost
259
279
. findDeclaration ( modulePath , module . className , containingFile ) ;
260
280
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
- } ) ;
281
+ const loadChildrenRoute : LazyRoute [ ] = this . extractLoadChildren ( entryNgModuleMetadata )
282
+ . map ( route => {
283
+ const mr = ModuleRoute . fromString ( route ) ;
284
+ const relativePath = this . _resolveModulePath ( mr , relativeModulePath ) ;
285
+ const absolutePath = path . join ( this . genDir , relativePath ) ;
286
+ return {
287
+ moduleRoute : mr ,
288
+ moduleRelativePath : relativePath ,
289
+ moduleAbsolutePath : absolutePath
290
+ } ;
291
+ } ) ;
292
+ const resultMap : LazyRouteMap = loadChildrenRoute
293
+ . reduce ( ( acc : LazyRouteMap , curr : LazyRoute ) => {
294
+ const key = curr . moduleRoute . path ;
295
+ if ( acc [ key ] ) {
296
+ if ( acc [ key ] . moduleAbsolutePath != curr . moduleAbsolutePath ) {
297
+ throw new Error ( `Duplicated path in loadChildren detected: "${ key } " is used in 2 ` +
298
+ 'loadChildren, but they point to different modules. Webpack cannot distinguish ' +
299
+ 'between the two based on context and would fail to load the proper one.' ) ;
300
+ }
301
+ } else {
302
+ acc [ key ] = curr ;
303
+ }
304
+ return acc ;
305
+ } , { } ) ;
265
306
266
307
// 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 ) ;
308
+ for ( const lazyRoute of loadChildrenRoute ) {
309
+ const mr = lazyRoute . moduleRoute ;
310
+ const children = this . _processNgModule ( mr , relativeModulePath ) ;
311
+ Object . keys ( children ) . forEach ( p => {
312
+ const child = children [ p ] ;
313
+ const key = child . moduleRoute . path ;
314
+ if ( resultMap [ key ] ) {
315
+ if ( resultMap [ key ] . moduleAbsolutePath != child . moduleAbsolutePath ) {
316
+ throw new Error ( `Duplicated path in loadChildren detected: "${ key } " is used in 2 ` +
317
+ 'loadChildren, but they point to different modules. Webpack cannot distinguish ' +
318
+ 'between the two based on context and would fail to load the proper one.' ) ;
319
+ }
320
+ } else {
321
+ resultMap [ key ] = child ;
322
+ }
323
+ } ) ;
271
324
}
272
- return result ;
325
+ return resultMap ;
273
326
}
274
327
275
328
private getNgModuleMetadata ( staticSymbol : ngCompiler . StaticSymbol ) {
@@ -281,10 +334,23 @@ export class AotPlugin {
281
334
}
282
335
283
336
private extractLoadChildren ( ngModuleDecorator : any ) : any [ ] {
284
- const routes = ngModuleDecorator . imports . reduce ( ( mem : any [ ] , m : any ) => {
337
+ const routes = ( ngModuleDecorator . imports || [ ] ) . reduce ( ( mem : any [ ] , m : any ) => {
285
338
return mem . concat ( this . collectRoutes ( m . providers ) ) ;
286
339
} , this . collectRoutes ( ngModuleDecorator . providers ) ) ;
287
- return this . collectLoadChildren ( routes ) ;
340
+ return this . collectLoadChildren ( routes )
341
+ . concat ( ( ngModuleDecorator . imports || [ ] )
342
+ // Also recursively extractLoadChildren of modules we import.
343
+ . map ( ( staticSymbol : any ) => {
344
+ if ( staticSymbol instanceof StaticSymbol ) {
345
+ const entryNgModuleMetadata = this . getNgModuleMetadata ( staticSymbol ) ;
346
+ return this . extractLoadChildren ( entryNgModuleMetadata ) ;
347
+ } else {
348
+ return [ ] ;
349
+ }
350
+ } )
351
+ // Poor man's flat map.
352
+ . reduce ( ( acc : any [ ] , i : any ) => acc . concat ( i ) , [ ] ) )
353
+ . filter ( x => ! ! x ) ;
288
354
}
289
355
290
356
private collectRoutes ( providers : any [ ] ) : any [ ] {
0 commit comments