@@ -11,6 +11,7 @@ import {WebpackCompilerHost} from './compiler_host';
1111import { resolveEntryModuleFromMain } from './entry_resolver' ;
1212import { Tapable } from './webpack' ;
1313import { PathsPlugin } from './paths-plugin' ;
14+ import { findLazyRoutes , LazyRouteMap } from './lazy_routes' ;
1415
1516
1617/**
@@ -39,7 +40,7 @@ export class AotPlugin implements Tapable {
3940 private _rootFilePath : string [ ] ;
4041 private _compilerHost : WebpackCompilerHost ;
4142 private _resourceLoader : WebpackResourceLoader ;
42- private _lazyRoutes : { [ route : string ] : string } ;
43+ private _lazyRoutes : { [ route : string ] : string } = Object . create ( null ) ;
4344 private _tsConfigPath : string ;
4445 private _entryModule : string ;
4546
@@ -56,6 +57,8 @@ export class AotPlugin implements Tapable {
5657 private _i18nFormat : string ;
5758 private _locale : string ;
5859
60+ private _firstRun : boolean = true ;
61+
5962 constructor ( options : AotPluginOptions ) {
6063 this . _setupOptions ( options ) ;
6164 }
@@ -78,6 +81,7 @@ export class AotPlugin implements Tapable {
7881 get i18nFile ( ) { return this . _i18nFile ; }
7982 get i18nFormat ( ) { return this . _i18nFormat ; }
8083 get locale ( ) { return this . _locale ; }
84+ get firstRun ( ) { return this . _firstRun ; }
8185
8286 private _setupOptions ( options : AotPluginOptions ) {
8387 // Fill in the missing options.
@@ -194,6 +198,28 @@ export class AotPlugin implements Tapable {
194198 }
195199 }
196200
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+
197223 // registration hook for webpack plugin
198224 apply ( compiler : any ) {
199225 this . _compiler = compiler ;
@@ -220,7 +246,15 @@ export class AotPlugin implements Tapable {
220246 result . dependencies . forEach ( ( d : any ) => d . critical = false ) ;
221247 result . resolveDependencies = ( p1 : any , p2 : any , p3 : any , p4 : RegExp , cb : any ) => {
222248 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 ) ;
224258 cb ( null , dependencies ) ;
225259 } ;
226260 return callback ( null , result ) ;
@@ -312,19 +346,24 @@ export class AotPlugin implements Tapable {
312346 . then ( ( ) => {
313347 // Populate the file system cache with the virtual module.
314348 this . _compilerHost . populateWebpackResolver ( this . _compiler . resolvers . normal ) ;
349+ this . _compilerHost . resetChangedFileTracker ( ) ;
315350 } )
316351 . 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 )
326365 . forEach ( k => {
327- const lazyRoute = allLazyRoutes [ k ] ;
366+ const lazyRoute = discoveredLazyRoutes [ k ] ;
328367 k = k . split ( '#' ) [ 0 ] ;
329368 if ( this . skipCodeGeneration ) {
330369 this . _lazyRoutes [ k ] = lazyRoute ;
@@ -334,7 +373,11 @@ export class AotPlugin implements Tapable {
334373 }
335374 } ) ;
336375 } )
337- . then ( ( ) => cb ( ) , ( err : any ) => {
376+ . then ( ( ) => {
377+ this . _firstRun = false ;
378+ cb ( ) ;
379+ } , ( err : any ) => {
380+ this . _firstRun = false ;
338381 compilation . errors . push ( err ) ;
339382 cb ( ) ;
340383 } ) ;
0 commit comments