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
This commit is contained in:
Meligy 2016-12-31 20:25:47 +11:00 committed by Matias Niemelä
parent d061adc02d
commit 5d9cbd7d6f
4 changed files with 54 additions and 20 deletions

View File

@ -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 {
}

View File

@ -16,7 +16,10 @@ export class LazyFeatureComponent {
@NgModule({ @NgModule({
imports: [RouterModule.forChild([ imports: [RouterModule.forChild([
{path: '', component: LazyFeatureComponent, pathMatch: 'full'}, {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] declarations: [LazyFeatureComponent]
}) })

View File

@ -191,6 +191,8 @@ function lazyRoutesTest() {
'./lazy.module#LazyModule': 'lazy.module.ts', './lazy.module#LazyModule': 'lazy.module.ts',
'./feature/feature.module#FeatureModule': 'feature/feature.module.ts', './feature/feature.module#FeatureModule': 'feature/feature.module.ts',
'./feature/lazy-feature.module#LazyFeatureModule': 'feature/lazy-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', 'feature2/feature2.module#Feature2Module': 'feature2/feature2.module.ts',
'./default.module': 'feature2/default.module.ts', './default.module': 'feature2/default.module.ts',
'feature/feature.module#FeatureModule': 'feature/feature.module.ts' 'feature/feature.module#FeatureModule': 'feature/feature.module.ts'

View File

@ -15,8 +15,6 @@
import {AotCompilerHost, StaticReflector, StaticSymbol} from '@angular/compiler'; import {AotCompilerHost, StaticReflector, StaticSymbol} from '@angular/compiler';
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
// We cannot depend directly to @angular/router. // We cannot depend directly to @angular/router.
type Route = any; type Route = any;
const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader'; const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader';
@ -63,29 +61,37 @@ export function listLazyRoutesOfModule(
const className = entryRouteDef.className; const className = entryRouteDef.className;
// List loadChildren of this single module. // 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 ROUTES = reflector.findDeclaration(ROUTER_MODULE_PATH, ROUTER_ROUTES_SYMBOL_NAME);
const lazyRoutes: LazyRoute[] = const lazyRoutes: LazyRoute[] =
_extractLazyRoutesFromStaticModule(staticSymbol, reflector, host, ROUTES); _extractLazyRoutesFromStaticModule(appStaticSymbol, reflector, host, ROUTES);
const routes: LazyRouteMap = {};
lazyRoutes.forEach((lazyRoute: LazyRoute) => { const allLazyRoutes = lazyRoutes.reduce(
const route: string = lazyRoute.routeDef.toString(); function includeLazyRouteAndSubRoutes(allRoutes: LazyRouteMap, lazyRoute: LazyRoute):
_assertRoute(routes, lazyRoute); LazyRouteMap {
routes[route] = lazyRoute; const route: string = lazyRoute.routeDef.toString();
_assertRoute(allRoutes, lazyRoute);
allRoutes[route] = lazyRoute;
const lazyModuleSymbol = reflector.findDeclaration( // StaticReflector does not support discovering annotations like `NgModule` on default
lazyRoute.absoluteFilePath, lazyRoute.routeDef.className || 'default'); // exports
const subRoutes = _extractLazyRoutesFromStaticModule(lazyModuleSymbol, reflector, host, ROUTES); // 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. const lazyModuleSymbol = reflector.findDeclaration(
subRoutes.forEach(subRoute => { lazyRoute.absoluteFilePath, lazyRoute.routeDef.className || 'default');
_assertRoute(routes, subRoute);
routes[subRoute.routeDef.toString()] = subRoute;
});
});
return routes; const subRoutes =
_extractLazyRoutesFromStaticModule(lazyModuleSymbol, reflector, host, ROUTES);
return subRoutes.reduce(includeLazyRouteAndSubRoutes, allRoutes);
},
{});
return allLazyRoutes;
} }