diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index 54a2c6d654..1b8ca25bb7 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -21,7 +21,7 @@ import {ImportRewriter, ModuleResolver, NoopImportRewriter, R3SymbolsImportRewri import {PartialEvaluator} from './partial_evaluator'; import {TypeScriptReflectionHost} from './reflection'; import {HostResourceLoader} from './resource_loader'; -import {NgModuleRouteAnalyzer} from './routing'; +import {NgModuleRouteAnalyzer, entryPointKeyFor} from './routing'; import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims'; import {ivySwitchTransform} from './switch'; import {IvyCompilation, declarationTransformFactory, ivyTransformFactory} from './transform'; @@ -191,6 +191,38 @@ export class NgtscProgram implements api.Program { } listLazyRoutes(entryRoute?: string|undefined): api.LazyRoute[] { + if (entryRoute) { + // Note: + // This resolution step is here to match the implementation of the old `AotCompilerHost` (see + // https://github.com/angular/angular/blob/50732e156/packages/compiler-cli/src/transformers/compiler_host.ts#L175-L188). + // + // `@angular/cli` will always call this API with an absolute path, so the resolution step is + // not necessary, but keeping it backwards compatible in case someone else is using the API. + + // Relative entry paths are disallowed. + if (entryRoute.startsWith('.')) { + throw new Error( + `Falied to list lazy routes: Resolution of relative paths (${entryRoute}) is not supported.`); + } + + // Non-relative entry paths fall into one of the following categories: + // - Absolute system paths (e.g. `/foo/bar/my-project/my-module`), which are unaffected by the + // logic below. + // - Paths to enternal modules (e.g. `some-lib`). + // - Paths mapped to directories in `tsconfig.json` (e.g. `shared/my-module`). + // (See https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping.) + // + // In all cases above, the `containingFile` argument is ignored, so we can just take the first + // of the root files. + const containingFile = this.tsProgram.getRootFileNames()[0]; + const [entryPath, moduleName] = entryRoute.split('#'); + const resolved = ts.resolveModuleName(entryPath, containingFile, this.options, this.host); + + if (resolved.resolvedModule) { + entryRoute = entryPointKeyFor(resolved.resolvedModule.resolvedFileName, moduleName); + } + } + this.ensureAnalyzed(); return this.routeAnalyzer !.listLazyRoutes(entryRoute); } diff --git a/packages/compiler-cli/src/ngtsc/routing/index.ts b/packages/compiler-cli/src/ngtsc/routing/index.ts index 8207371d26..fbab4f94c7 100644 --- a/packages/compiler-cli/src/ngtsc/routing/index.ts +++ b/packages/compiler-cli/src/ngtsc/routing/index.ts @@ -9,3 +9,4 @@ /// export {LazyRoute, NgModuleRouteAnalyzer} from './src/analyzer'; +export {entryPointKeyFor} from './src/route'; diff --git a/packages/compiler-cli/test/ngtools_api_spec.ts b/packages/compiler-cli/test/ngtools_api_spec.ts index 7f3f97250c..6ceeb355be 100644 --- a/packages/compiler-cli/test/ngtools_api_spec.ts +++ b/packages/compiler-cli/test/ngtools_api_spec.ts @@ -37,7 +37,7 @@ describe('ngtools_api (deprecated)', () => { export class ErrorComp2 {} @NgModule({ - declarations: [ErrorComp2, NonExistentComp], + declarations: [ErrorComp2], imports: [RouterModule.forRoot([{loadChildren: './child#ChildModule'}])] }) export class MainModule {} @@ -60,7 +60,7 @@ describe('ngtools_api (deprecated)', () => { }); } - fixmeIvy('FW-629: ngtsc lists lazy routes').it('should list lazy routes recursively', () => { + it('should list lazy routes recursively', () => { writeSomeRoutes(); const {program, host, options} = createProgram(['src/main.ts', 'src/child.ts', 'src/child2.ts']);