From 5d9cbd7d6f20dc0d63bd297ccaf68bd0257cb4b8 Mon Sep 17 00:00:00 2001 From: Meligy Date: Sat, 31 Dec 2016 20:25:47 +1100 Subject: [PATCH] fix(compiler-cli): add support for more than 2 levels of nested lazy routes This change adds Compiler CLI support for any level of nesting for lazy routes. For example `{app-root}/lazy-loaded-module-1/lazy-loaded-module-2/lazy-loaded-module-3` Where `lazy-loaded-module-3` is lazy loaded from `lazy-loaded-module-2`, and `lazy-loaded-module-2` is lazy loaded from module `lazy-loaded-module-1`, and `lazy-loaded-module-1` is lazy loaded from `AppModule` Fixes angular/angular-cli#3663 --- .../feature/lazy-feature-nested.module.ts | 23 ++++++++++ .../feature/lazy-feature.module.ts | 5 ++- .../integrationtest/test/test_ngtools_api.ts | 2 + .../@angular/compiler-cli/src/ngtools_impl.ts | 44 +++++++++++-------- 4 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature-nested.module.ts diff --git a/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature-nested.module.ts b/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature-nested.module.ts new file mode 100644 index 0000000000..87e664fdbe --- /dev/null +++ b/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature-nested.module.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; + +@Component({selector: 'lazy-feature-comp', template: 'lazy feature, nested!'}) +export class LazyFeatureNestedComponent { +} + +@NgModule({ + imports: [RouterModule.forChild([ + {path: '', component: LazyFeatureNestedComponent, pathMatch: 'full'}, + ])], + declarations: [LazyFeatureNestedComponent] +}) +export class LazyFeatureNestedModule { +} diff --git a/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts b/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts index b57fa30107..64e9bc4488 100644 --- a/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts +++ b/modules/@angular/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts @@ -16,7 +16,10 @@ export class LazyFeatureComponent { @NgModule({ imports: [RouterModule.forChild([ {path: '', component: LazyFeatureComponent, pathMatch: 'full'}, - {path: 'feature', loadChildren: './feature.module#FeatureModule'} + {path: 'feature', loadChildren: './feature.module#FeatureModule'}, { + path: 'nested-feature', + loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule' + } ])], declarations: [LazyFeatureComponent] }) diff --git a/modules/@angular/compiler-cli/integrationtest/test/test_ngtools_api.ts b/modules/@angular/compiler-cli/integrationtest/test/test_ngtools_api.ts index 99d1a31116..36fbf8afa5 100644 --- a/modules/@angular/compiler-cli/integrationtest/test/test_ngtools_api.ts +++ b/modules/@angular/compiler-cli/integrationtest/test/test_ngtools_api.ts @@ -191,6 +191,8 @@ function lazyRoutesTest() { './lazy.module#LazyModule': 'lazy.module.ts', './feature/feature.module#FeatureModule': 'feature/feature.module.ts', './feature/lazy-feature.module#LazyFeatureModule': 'feature/lazy-feature.module.ts', + './feature.module#FeatureModule': 'feature/feature.module.ts', + './lazy-feature-nested.module#LazyFeatureNestedModule': 'feature/lazy-feature-nested.module.ts', 'feature2/feature2.module#Feature2Module': 'feature2/feature2.module.ts', './default.module': 'feature2/default.module.ts', 'feature/feature.module#FeatureModule': 'feature/feature.module.ts' diff --git a/modules/@angular/compiler-cli/src/ngtools_impl.ts b/modules/@angular/compiler-cli/src/ngtools_impl.ts index 9b81320fd2..fea594bfe3 100644 --- a/modules/@angular/compiler-cli/src/ngtools_impl.ts +++ b/modules/@angular/compiler-cli/src/ngtools_impl.ts @@ -15,8 +15,6 @@ import {AotCompilerHost, StaticReflector, StaticSymbol} from '@angular/compiler'; import {NgModule} from '@angular/core'; - - // We cannot depend directly to @angular/router. type Route = any; const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader'; @@ -63,29 +61,37 @@ export function listLazyRoutesOfModule( const className = entryRouteDef.className; // List loadChildren of this single module. - const staticSymbol = reflector.findDeclaration(modulePath, className, containingFile); + const appStaticSymbol = reflector.findDeclaration(modulePath, className, containingFile); const ROUTES = reflector.findDeclaration(ROUTER_MODULE_PATH, ROUTER_ROUTES_SYMBOL_NAME); const lazyRoutes: LazyRoute[] = - _extractLazyRoutesFromStaticModule(staticSymbol, reflector, host, ROUTES); - const routes: LazyRouteMap = {}; + _extractLazyRoutesFromStaticModule(appStaticSymbol, reflector, host, ROUTES); - lazyRoutes.forEach((lazyRoute: LazyRoute) => { - const route: string = lazyRoute.routeDef.toString(); - _assertRoute(routes, lazyRoute); - routes[route] = lazyRoute; + const allLazyRoutes = lazyRoutes.reduce( + function includeLazyRouteAndSubRoutes(allRoutes: LazyRouteMap, lazyRoute: LazyRoute): + LazyRouteMap { + const route: string = lazyRoute.routeDef.toString(); + _assertRoute(allRoutes, lazyRoute); + allRoutes[route] = lazyRoute; - const lazyModuleSymbol = reflector.findDeclaration( - lazyRoute.absoluteFilePath, lazyRoute.routeDef.className || 'default'); - const subRoutes = _extractLazyRoutesFromStaticModule(lazyModuleSymbol, reflector, host, ROUTES); + // StaticReflector does not support discovering annotations like `NgModule` on default + // exports + // Which means: if a default export NgModule was lazy-loaded, we can discover it, but, + // we cannot parse its routes to see if they have loadChildren or not. + if (!lazyRoute.routeDef.className) { + return allRoutes; + } - // Populate the map using the routes we just found. - subRoutes.forEach(subRoute => { - _assertRoute(routes, subRoute); - routes[subRoute.routeDef.toString()] = subRoute; - }); - }); + const lazyModuleSymbol = reflector.findDeclaration( + lazyRoute.absoluteFilePath, lazyRoute.routeDef.className || 'default'); - return routes; + const subRoutes = + _extractLazyRoutesFromStaticModule(lazyModuleSymbol, reflector, host, ROUTES); + + return subRoutes.reduce(includeLazyRouteAndSubRoutes, allRoutes); + }, + {}); + + return allLazyRoutes; }