@@ -11,6 +11,7 @@ import {WebpackCompilerHost} from './compiler_host';
11
11
import { resolveEntryModuleFromMain } from './entry_resolver' ;
12
12
import { Tapable } from './webpack' ;
13
13
import { PathsPlugin } from './paths-plugin' ;
14
+ import { findLazyRoutes , LazyRouteMap } from './lazy_routes' ;
14
15
15
16
16
17
/**
@@ -39,7 +40,7 @@ export class AotPlugin implements Tapable {
39
40
private _rootFilePath : string [ ] ;
40
41
private _compilerHost : WebpackCompilerHost ;
41
42
private _resourceLoader : WebpackResourceLoader ;
42
- private _lazyRoutes : { [ route : string ] : string } ;
43
+ private _lazyRoutes : { [ route : string ] : string } = Object . create ( null ) ;
43
44
private _tsConfigPath : string ;
44
45
private _entryModule : string ;
45
46
@@ -56,6 +57,8 @@ export class AotPlugin implements Tapable {
56
57
private _i18nFormat : string ;
57
58
private _locale : string ;
58
59
60
+ private _firstRun : boolean = true ;
61
+
59
62
constructor ( options : AotPluginOptions ) {
60
63
this . _setupOptions ( options ) ;
61
64
}
@@ -78,6 +81,7 @@ export class AotPlugin implements Tapable {
78
81
get i18nFile ( ) { return this . _i18nFile ; }
79
82
get i18nFormat ( ) { return this . _i18nFormat ; }
80
83
get locale ( ) { return this . _locale ; }
84
+ get firstRun ( ) { return this . _firstRun ; }
81
85
82
86
private _setupOptions ( options : AotPluginOptions ) {
83
87
// Fill in the missing options.
@@ -194,6 +198,28 @@ export class AotPlugin implements Tapable {
194
198
}
195
199
}
196
200
201
+ private _findLazyRoutesInAst ( ) : LazyRouteMap {
202
+ const result : LazyRouteMap = Object . create ( null ) ;
203
+ const changedFilePaths = this . _compilerHost . getChangedFilePaths ( ) ;
204
+ for ( const filePath in changedFilePaths ) {
205
+ const fileLazyRoutes = findLazyRoutes ( filePath , this . _program , this . _compilerHost ) ;
206
+ for ( const routeKey of Object . keys ( fileLazyRoutes ) ) {
207
+ const route = fileLazyRoutes [ routeKey ] ;
208
+ if ( routeKey in this . _lazyRoutes ) {
209
+ if ( route === null ) {
210
+ this . _lazyRoutes [ routeKey ] = null ;
211
+ } else if ( this . _lazyRoutes [ routeKey ] !== route ) {
212
+ throw new Error ( `Duplicated path in loadChildren detected: "${ routeKey } " is used in 2 `
213
+ + `loadChildren, but they point to different modules `
214
+ + `("${ this . _lazyRoutes [ routeKey ] } " and "${ route } "). Webpack cannot `
215
+ + `distinguish on context and would fail to load the proper one.` ) ;
216
+ }
217
+ }
218
+ }
219
+ }
220
+ return result ;
221
+ }
222
+
197
223
// registration hook for webpack plugin
198
224
apply ( compiler : any ) {
199
225
this . _compiler = compiler ;
@@ -220,7 +246,15 @@ export class AotPlugin implements Tapable {
220
246
result . dependencies . forEach ( ( d : any ) => d . critical = false ) ;
221
247
result . resolveDependencies = ( p1 : any , p2 : any , p3 : any , p4 : RegExp , cb : any ) => {
222
248
const dependencies = Object . keys ( this . _lazyRoutes )
223
- . map ( ( key ) => new ContextElementDependency ( this . _lazyRoutes [ key ] , key ) ) ;
249
+ . map ( ( key ) => {
250
+ const value = this . _lazyRoutes [ key ] ;
251
+ if ( value !== null ) {
252
+ return new ContextElementDependency ( value , key ) ;
253
+ } else {
254
+ return null ;
255
+ }
256
+ } )
257
+ . filter ( x => ! ! x ) ;
224
258
cb ( null , dependencies ) ;
225
259
} ;
226
260
return callback ( null , result ) ;
@@ -312,19 +346,24 @@ export class AotPlugin implements Tapable {
312
346
. then ( ( ) => {
313
347
// Populate the file system cache with the virtual module.
314
348
this . _compilerHost . populateWebpackResolver ( this . _compiler . resolvers . normal ) ;
349
+ this . _compilerHost . resetChangedFileTracker ( ) ;
315
350
} )
316
351
. then ( ( ) => {
317
- // Process the lazy routes
318
- this . _lazyRoutes = { } ;
319
- const allLazyRoutes = __NGTOOLS_PRIVATE_API_2 . listLazyRoutes ( {
320
- program : this . _program ,
321
- host : this . _compilerHost ,
322
- angularCompilerOptions : this . _angularCompilerOptions ,
323
- entryModule : this . _entryModule
324
- } ) ;
325
- Object . keys ( allLazyRoutes )
352
+ // We need to run the `listLazyRoutes` the first time because it also navigates libraries
353
+ // and other things that we might miss using the findLazyRoutesInAst.
354
+ let discoveredLazyRoutes : LazyRouteMap = this . firstRun
355
+ ? __NGTOOLS_PRIVATE_API_2 . listLazyRoutes ( {
356
+ program : this . _program ,
357
+ host : this . _compilerHost ,
358
+ angularCompilerOptions : this . _angularCompilerOptions ,
359
+ entryModule : this . _entryModule
360
+ } )
361
+ : this . _findLazyRoutesInAst ( ) ;
362
+
363
+ // Process the lazy routes discovered.
364
+ Object . keys ( discoveredLazyRoutes )
326
365
. forEach ( k => {
327
- const lazyRoute = allLazyRoutes [ k ] ;
366
+ const lazyRoute = discoveredLazyRoutes [ k ] ;
328
367
k = k . split ( '#' ) [ 0 ] ;
329
368
if ( this . skipCodeGeneration ) {
330
369
this . _lazyRoutes [ k ] = lazyRoute ;
@@ -334,7 +373,11 @@ export class AotPlugin implements Tapable {
334
373
}
335
374
} ) ;
336
375
} )
337
- . then ( ( ) => cb ( ) , ( err : any ) => {
376
+ . then ( ( ) => {
377
+ this . _firstRun = false ;
378
+ cb ( ) ;
379
+ } , ( err : any ) => {
380
+ this . _firstRun = false ;
338
381
compilation . errors . push ( err ) ;
339
382
cb ( ) ;
340
383
} ) ;
0 commit comments