diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index acb76edda3..bf014a6d57 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -263,10 +263,7 @@ class AngularCompilerProgram implements Program { } private generateStubs() { - return this.options.skipTemplateCodegen ? [] : - this.options.generateCodeForLibraries === false ? - this.compiler.emitPartialStubs(this.analyzedModules) : - this.compiler.emitAllStubs(this.analyzedModules); + return this.options.skipTemplateCodegen ? [] : this.compiler.emitAllStubs(this.analyzedModules); } private generateFiles() { diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index 893068872b..8c93ce53f9 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -716,11 +716,13 @@ describe('ngc transformer command-line', () => { } }; beforeEach(() => { - const writeConfig = (dir: string) => { - write(path.join(dir, 'tsconfig.json'), ` + const writeConfig = + (dir: string, generateCodeForLibraries = false, includes: string[] = [], + excludes: string[] = []) => { + write(path.join(dir, 'tsconfig.json'), ` { "angularCompilerOptions": { - "generateCodeForLibraries": true, + "generateCodeForLibraries": ${generateCodeForLibraries}, "enableSummariesForJit": true }, "compilerOptions": { @@ -735,11 +737,18 @@ describe('ngc transformer command-line', () => { "paths": { "lib1/*": ["../lib1/*"], "lib2/*": ["../lib2/*"] }, "typeRoots": [] } + ${includes.length?',"include":["' + includes.join('","')+'"]':''} + ${excludes.length?',"exclude":["' + excludes.join('","')+'"]':''} }`); - }; + }; + + // Angular + writeConfig( + 'ng', /* generateCodeForLibraries */ true, ['../node_modules/@angular/core/**/*'], + ['../node_modules/@angular/core/test/**', '../node_modules/@angular/core/testing/**']); // Lib 1 - writeConfig('lib1'); + writeConfig('lib1', /* generateCodeForLibraries */ false); write('lib1/module.ts', ` import {NgModule} from '@angular/core'; @@ -752,7 +761,7 @@ describe('ngc transformer command-line', () => { `); // Lib 2 - writeConfig('lib2'); + writeConfig('lib2', /* generateCodeForLibraries */ false); write('lib2/module.ts', ` export {Module} from 'lib1/module'; `); @@ -773,6 +782,7 @@ describe('ngc transformer command-line', () => { }); it('should be able to compile library 1', () => { + expect(mainSync(['-p', path.join(basePath, 'ng')], errorSpy)).toBe(0); expect(mainSync(['-p', path.join(basePath, 'lib1')], errorSpy)).toBe(0); shouldExist('lib1/module.js'); shouldExist('lib1/module.ngsummary.json'); @@ -783,6 +793,7 @@ describe('ngc transformer command-line', () => { }); it('should be able to compile library 2', () => { + expect(mainSync(['-p', path.join(basePath, 'ng')], errorSpy)).toBe(0); expect(mainSync(['-p', path.join(basePath, 'lib1')], errorSpy)).toBe(0); expect(mainSync(['-p', path.join(basePath, 'lib2')], errorSpy)).toBe(0); shouldExist('lib2/module.js'); @@ -795,6 +806,7 @@ describe('ngc transformer command-line', () => { describe('building an application', () => { beforeEach(() => { + expect(mainSync(['-p', path.join(basePath, 'ng')], errorSpy)).toBe(0); expect(mainSync(['-p', path.join(basePath, 'lib1')], errorSpy)).toBe(0); expect(mainSync(['-p', path.join(basePath, 'lib2')], errorSpy)).toBe(0); }); diff --git a/packages/compiler/src/aot/compiler.ts b/packages/compiler/src/aot/compiler.ts index 76d3aca8df..23fa187374 100644 --- a/packages/compiler/src/aot/compiler.ts +++ b/packages/compiler/src/aot/compiler.ts @@ -64,16 +64,7 @@ export class AotCompiler { emitAllStubs(analyzeResult: NgAnalyzedModules): GeneratedFile[] { const {files} = analyzeResult; const sourceModules = files.map( - file => - this._compileStubFile(file.srcUrl, file.directives, file.pipes, file.ngModules, false)); - return flatten(sourceModules); - } - - emitPartialStubs(analyzeResult: NgAnalyzedModules): GeneratedFile[] { - const {files} = analyzeResult; - const sourceModules = files.map( - file => - this._compileStubFile(file.srcUrl, file.directives, file.pipes, file.ngModules, true)); + file => this._compileStubFile(file.srcUrl, file.directives, file.pipes, file.ngModules)); return flatten(sourceModules); } @@ -88,18 +79,7 @@ export class AotCompiler { private _compileStubFile( srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[], - ngModules: StaticSymbol[], partial: boolean): GeneratedFile[] { - // partial is true when we only need the files we are certain will produce a factory and/or - // summary. - // This is the normal case for `ngc` but if we assume libraryies are generating their own - // factories - // then we might need a factory for a file that re-exports a module or factory which we cannot - // know - // ahead of time so we need a stub generate for all non-.d.ts files. The .d.ts files do not need - // to - // be excluded here because they are excluded when the modules are analyzed. If a factory ends - // up - // not being needed, the factory file is not written in writeFile callback. + ngModules: StaticSymbol[]): GeneratedFile[] { const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1]; const generatedFiles: GeneratedFile[] = []; @@ -112,16 +92,11 @@ export class AotCompiler { createForJitStub(jitSummaryOutputCtx, ngModuleReference); }); - let partialJitStubRequired = false; - let partialFactoryStubRequired = false; - // create stubs for external stylesheets (always empty, as users should not import anything from // the generated code) directives.forEach((dirType) => { const compMeta = this._metadataResolver.getDirectiveMetadata(dirType); - partialJitStubRequired = true; - if (!compMeta.isComponent) { return; } @@ -129,20 +104,16 @@ export class AotCompiler { compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => { const styleContext = this._createOutputContext(_stylesModuleUrl( stylesheetMeta.moduleUrl !, this._styleCompiler.needsStyleShim(compMeta), fileSuffix)); - _createTypeReferenceStub(styleContext, Identifiers.ComponentFactory); + _createStub(styleContext); generatedFiles.push(this._codegenSourceModule(stylesheetMeta.moduleUrl !, styleContext)); }); - - partialFactoryStubRequired = true; }); - // If we need all the stubs to be generated then insert an arbitrary reference into the stub - if ((partialFactoryStubRequired || !partial) && ngFactoryOutputCtx.statements.length <= 0) { - _createTypeReferenceStub(ngFactoryOutputCtx, Identifiers.ComponentFactory); + if (ngFactoryOutputCtx.statements.length <= 0) { + _createStub(ngFactoryOutputCtx); } - if ((partialJitStubRequired || !partial || (pipes && pipes.length > 0)) && - jitSummaryOutputCtx.statements.length <= 0) { - _createTypeReferenceStub(jitSummaryOutputCtx, Identifiers.ComponentFactory); + if (jitSummaryOutputCtx.statements.length <= 0) { + _createStub(jitSummaryOutputCtx); } // Note: we are creating stub ngfactory/ngsummary for all source files, @@ -390,8 +361,11 @@ export class AotCompiler { } } -function _createTypeReferenceStub(outputCtx: OutputContext, reference: o.ExternalReference) { - outputCtx.statements.push(o.importExpr(reference).toStmt()); +function _createStub(outputCtx: OutputContext) { + // Note: We need to produce at least one import statement so that + // TypeScript knows that the file is an es6 module. Otherwise our generated + // exports / imports won't be emitted properly by TypeScript. + outputCtx.statements.push(o.importExpr(Identifiers.ComponentFactory).toStmt()); } function _resolveStyleStatements(