From 16f90cac4b78d8a9207ecbbcf515518bc01cb7b2 Mon Sep 17 00:00:00 2001 From: JoostK Date: Sat, 14 Nov 2020 20:37:27 +0100 Subject: [PATCH] perf(compiler-cli): ensure module resolution cache is reused for type-check program (#39693) The Angular compiler creates two `ts.Program`s; one for emit and one for template type-checking. The creation of the type-check program could benefit from reusing the `ts.ModuleResolutionCache` that was primed during the creation of the emit program. This requires that the compiler host implements `resolveModuleNames`, as otherwise TypeScript will setup a `ts.ModuleResolutionHost` of its own for both programs. This commit ensures that `resolveModuleNames` is always implemented, even if the originally provided compiler host does not. This is beneficial for the `ngc` binary. PR Close #39693 --- .../compiler-cli/src/ngtsc/core/src/host.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/compiler-cli/src/ngtsc/core/src/host.ts b/packages/compiler-cli/src/ngtsc/core/src/host.ts index 24683b131b2..1dfeba4f187 100644 --- a/packages/compiler-cli/src/ngtsc/core/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/core/src/host.ts @@ -101,6 +101,12 @@ export class NgCompilerHost extends DelegatingCompilerHost implements this.constructionDiagnostics = diagnostics; this.inputFiles = [...inputFiles, ...shimAdapter.extraInputFiles]; this.rootDirs = rootDirs; + + if (this.resolveModuleNames === undefined) { + // In order to reuse the module resolution cache during the creation of the type-check + // program, we'll need to provide `resolveModuleNames` if the delegate did not provide one. + this.resolveModuleNames = this.createCachedResolveModuleNamesFunction(); + } } /** @@ -263,4 +269,17 @@ export class NgCompilerHost extends DelegatingCompilerHost implements get unifiedModulesHost(): UnifiedModulesHost|null { return this.fileNameToModuleName !== undefined ? this as UnifiedModulesHost : null; } + + private createCachedResolveModuleNamesFunction(): ts.CompilerHost['resolveModuleNames'] { + const moduleResolutionCache = ts.createModuleResolutionCache( + this.getCurrentDirectory(), this.getCanonicalFileName.bind(this)); + + return (moduleNames, containingFile, reusedNames, redirectedReference, options) => { + return moduleNames.map(moduleName => { + const module = ts.resolveModuleName( + moduleName, containingFile, options, this, moduleResolutionCache, redirectedReference); + return module.resolvedModule; + }); + }; + } }