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
This commit is contained in:
parent
2fbc92fd2e
commit
0262e37301
@ -263,10 +263,7 @@ class AngularCompilerProgram implements Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private generateStubs() {
|
private generateStubs() {
|
||||||
return this.options.skipTemplateCodegen ? [] :
|
return this.options.skipTemplateCodegen ? [] : this.compiler.emitAllStubs(this.analyzedModules);
|
||||||
this.options.generateCodeForLibraries === false ?
|
|
||||||
this.compiler.emitPartialStubs(this.analyzedModules) :
|
|
||||||
this.compiler.emitAllStubs(this.analyzedModules);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateFiles() {
|
private generateFiles() {
|
||||||
|
@ -716,11 +716,13 @@ describe('ngc transformer command-line', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const writeConfig = (dir: string) => {
|
const writeConfig =
|
||||||
write(path.join(dir, 'tsconfig.json'), `
|
(dir: string, generateCodeForLibraries = false, includes: string[] = [],
|
||||||
|
excludes: string[] = []) => {
|
||||||
|
write(path.join(dir, 'tsconfig.json'), `
|
||||||
{
|
{
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"generateCodeForLibraries": true,
|
"generateCodeForLibraries": ${generateCodeForLibraries},
|
||||||
"enableSummariesForJit": true
|
"enableSummariesForJit": true
|
||||||
},
|
},
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
@ -735,11 +737,18 @@ describe('ngc transformer command-line', () => {
|
|||||||
"paths": { "lib1/*": ["../lib1/*"], "lib2/*": ["../lib2/*"] },
|
"paths": { "lib1/*": ["../lib1/*"], "lib2/*": ["../lib2/*"] },
|
||||||
"typeRoots": []
|
"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
|
// Lib 1
|
||||||
writeConfig('lib1');
|
writeConfig('lib1', /* generateCodeForLibraries */ false);
|
||||||
write('lib1/module.ts', `
|
write('lib1/module.ts', `
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
@ -752,7 +761,7 @@ describe('ngc transformer command-line', () => {
|
|||||||
`);
|
`);
|
||||||
|
|
||||||
// Lib 2
|
// Lib 2
|
||||||
writeConfig('lib2');
|
writeConfig('lib2', /* generateCodeForLibraries */ false);
|
||||||
write('lib2/module.ts', `
|
write('lib2/module.ts', `
|
||||||
export {Module} from 'lib1/module';
|
export {Module} from 'lib1/module';
|
||||||
`);
|
`);
|
||||||
@ -773,6 +782,7 @@ describe('ngc transformer command-line', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to compile library 1', () => {
|
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);
|
expect(mainSync(['-p', path.join(basePath, 'lib1')], errorSpy)).toBe(0);
|
||||||
shouldExist('lib1/module.js');
|
shouldExist('lib1/module.js');
|
||||||
shouldExist('lib1/module.ngsummary.json');
|
shouldExist('lib1/module.ngsummary.json');
|
||||||
@ -783,6 +793,7 @@ describe('ngc transformer command-line', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to compile library 2', () => {
|
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, 'lib1')], errorSpy)).toBe(0);
|
||||||
expect(mainSync(['-p', path.join(basePath, 'lib2')], errorSpy)).toBe(0);
|
expect(mainSync(['-p', path.join(basePath, 'lib2')], errorSpy)).toBe(0);
|
||||||
shouldExist('lib2/module.js');
|
shouldExist('lib2/module.js');
|
||||||
@ -795,6 +806,7 @@ describe('ngc transformer command-line', () => {
|
|||||||
|
|
||||||
describe('building an application', () => {
|
describe('building an application', () => {
|
||||||
beforeEach(() => {
|
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, 'lib1')], errorSpy)).toBe(0);
|
||||||
expect(mainSync(['-p', path.join(basePath, 'lib2')], errorSpy)).toBe(0);
|
expect(mainSync(['-p', path.join(basePath, 'lib2')], errorSpy)).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -64,16 +64,7 @@ export class AotCompiler {
|
|||||||
emitAllStubs(analyzeResult: NgAnalyzedModules): GeneratedFile[] {
|
emitAllStubs(analyzeResult: NgAnalyzedModules): GeneratedFile[] {
|
||||||
const {files} = analyzeResult;
|
const {files} = analyzeResult;
|
||||||
const sourceModules = files.map(
|
const sourceModules = files.map(
|
||||||
file =>
|
file => this._compileStubFile(file.srcUrl, file.directives, file.pipes, file.ngModules));
|
||||||
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));
|
|
||||||
return flatten(sourceModules);
|
return flatten(sourceModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,18 +79,7 @@ export class AotCompiler {
|
|||||||
|
|
||||||
private _compileStubFile(
|
private _compileStubFile(
|
||||||
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
|
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
|
||||||
ngModules: StaticSymbol[], partial: boolean): GeneratedFile[] {
|
ngModules: StaticSymbol[]): 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.
|
|
||||||
const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1];
|
const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1];
|
||||||
const generatedFiles: GeneratedFile[] = [];
|
const generatedFiles: GeneratedFile[] = [];
|
||||||
|
|
||||||
@ -112,16 +92,11 @@ export class AotCompiler {
|
|||||||
createForJitStub(jitSummaryOutputCtx, ngModuleReference);
|
createForJitStub(jitSummaryOutputCtx, ngModuleReference);
|
||||||
});
|
});
|
||||||
|
|
||||||
let partialJitStubRequired = false;
|
|
||||||
let partialFactoryStubRequired = false;
|
|
||||||
|
|
||||||
// create stubs for external stylesheets (always empty, as users should not import anything from
|
// create stubs for external stylesheets (always empty, as users should not import anything from
|
||||||
// the generated code)
|
// the generated code)
|
||||||
directives.forEach((dirType) => {
|
directives.forEach((dirType) => {
|
||||||
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
|
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
|
||||||
|
|
||||||
partialJitStubRequired = true;
|
|
||||||
|
|
||||||
if (!compMeta.isComponent) {
|
if (!compMeta.isComponent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -129,20 +104,16 @@ export class AotCompiler {
|
|||||||
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
||||||
const styleContext = this._createOutputContext(_stylesModuleUrl(
|
const styleContext = this._createOutputContext(_stylesModuleUrl(
|
||||||
stylesheetMeta.moduleUrl !, this._styleCompiler.needsStyleShim(compMeta), fileSuffix));
|
stylesheetMeta.moduleUrl !, this._styleCompiler.needsStyleShim(compMeta), fileSuffix));
|
||||||
_createTypeReferenceStub(styleContext, Identifiers.ComponentFactory);
|
_createStub(styleContext);
|
||||||
generatedFiles.push(this._codegenSourceModule(stylesheetMeta.moduleUrl !, 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 (ngFactoryOutputCtx.statements.length <= 0) {
|
||||||
if ((partialFactoryStubRequired || !partial) && ngFactoryOutputCtx.statements.length <= 0) {
|
_createStub(ngFactoryOutputCtx);
|
||||||
_createTypeReferenceStub(ngFactoryOutputCtx, Identifiers.ComponentFactory);
|
|
||||||
}
|
}
|
||||||
if ((partialJitStubRequired || !partial || (pipes && pipes.length > 0)) &&
|
if (jitSummaryOutputCtx.statements.length <= 0) {
|
||||||
jitSummaryOutputCtx.statements.length <= 0) {
|
_createStub(jitSummaryOutputCtx);
|
||||||
_createTypeReferenceStub(jitSummaryOutputCtx, Identifiers.ComponentFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: we are creating stub ngfactory/ngsummary for all source files,
|
// 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) {
|
function _createStub(outputCtx: OutputContext) {
|
||||||
outputCtx.statements.push(o.importExpr(reference).toStmt());
|
// 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(
|
function _resolveStyleStatements(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user