From 1a647c399ba12cd2bd7391765892ea7cfef1699f Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Wed, 20 Sep 2017 16:31:02 -0700 Subject: [PATCH] fix(compiler): also create `.ngfactory.js` files in non obvious cases (#19301) E.g. when an exported class contains a ctor argument which is from another compilation unit. PR Close #19301 --- packages/compiler-cli/test/ngc_spec.ts | 14 ++++++++++++ packages/compiler/src/aot/compiler.ts | 31 +++++++++++++------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index 667febfef3..8d3a52040b 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -840,6 +840,7 @@ describe('ngc transformer command-line', () => { }) export class Module {} `); + write('lib1/class1.ts', `export class Class1 {}`); // Lib 2 write('lib2/tsconfig-lib2.json', `{ @@ -855,6 +856,13 @@ describe('ngc transformer command-line', () => { write('lib2/module.ts', ` export {Module} from 'lib1_built/module'; `); + write('lib2/class2.ts', ` + import {Class1} from 'lib1_built/class1'; + + export class Class2 { + constructor(class1: Class1) {} + } + `); // Application write('app/tsconfig-app.json', `{ @@ -904,6 +912,12 @@ describe('ngc transformer command-line', () => { shouldExist('lib2_built/module.ngfactory.js'); shouldExist('lib2_built/module.ngfactory.d.ts'); + shouldExist('lib2_built/class2.ngsummary.json'); + shouldNotExist('lib2_built/class2.ngsummary.js'); + shouldNotExist('lib2_built/class2.ngsummary.d.ts'); + shouldExist('lib2_built/class2.ngfactory.js'); + shouldExist('lib2_built/class2.ngfactory.d.ts'); + // app // make `shouldExist` / `shouldNotExist` relative to `built` outDir = path.resolve(basePath, 'built'); diff --git a/packages/compiler/src/aot/compiler.ts b/packages/compiler/src/aot/compiler.ts index aa21381d06..47e32dfe93 100644 --- a/packages/compiler/src/aot/compiler.ts +++ b/packages/compiler/src/aot/compiler.ts @@ -34,7 +34,7 @@ import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolv import {createForJitStub, serializeSummaries} from './summary_serializer'; import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName, summaryForJitFileName, summaryForJitName} from './util'; -export enum StubEmitFlags { +enum StubEmitFlags { Basic = 1 << 0, TypeCheck = 1 << 1, All = TypeCheck | Basic @@ -170,22 +170,14 @@ export class AotCompiler { } }); - // make sure we create a .ngfactory if we have a least one component - // in the file. + // Make sure we create a .ngfactory if we have a injectable/directive/pipe/NgModule + // or a reference to a non source file. + // Note: This is overestimating the required .ngfactory files as the real calculation is harder. // Only do this for StubEmitFlags.Basic, as adding a type check block // does not change this file (as we generate type check blocks based on NgModules). if (outputCtx.statements.length === 0 && (emitFlags & StubEmitFlags.Basic) && - file.directives.some( - dir => this._metadataResolver.getNonNormalizedDirectiveMetadata( - dir) !.metadata.isComponent)) { - _createEmptyStub(outputCtx); - } - - // make sure we create a .ngfactory if we reexport a non source file. - // Only do this for StubEmitFlags.Basic, as adding a type check block - // does not change this file (as we generate type check blocks based on NgModules). - if (outputCtx.statements.length === 0 && (emitFlags & StubEmitFlags.Basic) && - file.exportsNonSourceFiles) { + (file.directives.length || file.pipes.length || file.injectables.length || + file.ngModules.length || file.exportsNonSourceFiles)) { _createEmptyStub(outputCtx); } @@ -648,22 +640,29 @@ export function analyzeFile( if (!symbolMeta || symbolMeta.__symbolic === 'error') { return; } - exportsNonSourceFiles = - exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta); + let isNgSymbol = false; if (symbolMeta.__symbolic === 'class') { if (metadataResolver.isDirective(symbol)) { + isNgSymbol = true; directives.push(symbol); } else if (metadataResolver.isPipe(symbol)) { + isNgSymbol = true; pipes.push(symbol); } else if (metadataResolver.isInjectable(symbol)) { + isNgSymbol = true; injectables.push(symbol); } else { const ngModule = metadataResolver.getNgModuleMetadata(symbol, false); if (ngModule) { + isNgSymbol = true; ngModules.push(ngModule); } } } + if (!isNgSymbol) { + exportsNonSourceFiles = + exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta); + } }); } return {