Skip to content
Permalink
Browse files

fix(compiler): always emit ngfactories with reexports (#18788)

Previously, we only did this when setting the `generateCodeForLibraries: false`.

This is needed so that libraries compiled with `generateCodeForLibraries: true` can be used as dependencies of other compilation units.

PR Close #18788
  • Loading branch information...
tbosch authored and mhevery committed Aug 22, 2017
1 parent 2fbc92f commit 0262e3730194abbd12711e846c202d0329fa415b
@@ -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() {
@@ -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);
});
@@ -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,37 +92,28 @@ 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(<any>dirType);

partialJitStubRequired = true;

if (!compMeta.isComponent) {
return;
}
// Note: compMeta is a component and therefore template is non null.
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(

0 comments on commit 0262e37

Please sign in to comment.
You can’t perform that action at this time.