fix(compiler-cli): don't lower expressions in flat module metadata (#23226)

Lowering expressions in flat module metadata is desirable, but it won't
work without some rearchitecting. Currently the flat module index source
is added to the Program and therefore must be determined before the rest
of the transforms run. Since the lowering transform changes the set of
exports needed in the index, this creates a catch-22 in the index
generation.

This commit causes the flat module index metadata to be generated using
only those transforms which are "safe" (don't modify the index).

PR Close #23226
This commit is contained in:
Alex Rickabaugh 2018-04-06 08:23:40 -07:00 committed by Igor Minar
parent 195193b9be
commit 11ea3a3f33
2 changed files with 19 additions and 8 deletions

View File

@ -112,6 +112,8 @@ const MAX_TS_VERSION = '2.8.0';
class AngularCompilerProgram implements Program { class AngularCompilerProgram implements Program {
private rootNames: string[]; private rootNames: string[];
private metadataCache: MetadataCache; private metadataCache: MetadataCache;
// Metadata cache used exclusively for the flat module index
private flatModuleMetadataCache: MetadataCache;
private loweringMetadataTransform: LowerMetadataTransform; private loweringMetadataTransform: LowerMetadataTransform;
private oldProgramLibrarySummaries: Map<string, LibrarySummary>|undefined; private oldProgramLibrarySummaries: Map<string, LibrarySummary>|undefined;
private oldProgramEmittedGeneratedFiles: Map<string, GeneratedFile>|undefined; private oldProgramEmittedGeneratedFiles: Map<string, GeneratedFile>|undefined;
@ -149,7 +151,7 @@ class AngularCompilerProgram implements Program {
if (options.flatModuleOutFile) { if (options.flatModuleOutFile) {
const {host: bundleHost, indexName, errors} = const {host: bundleHost, indexName, errors} =
createBundleIndexHost(options, this.rootNames, host, () => this.metadataCache); createBundleIndexHost(options, this.rootNames, host, () => this.flatModuleMetadataCache);
if (errors) { if (errors) {
this._optionsDiagnostics.push(...errors.map(e => ({ this._optionsDiagnostics.push(...errors.map(e => ({
category: e.category, category: e.category,
@ -574,9 +576,12 @@ class AngularCompilerProgram implements Program {
customTransformers?: CustomTransformers): ts.CustomTransformers { customTransformers?: CustomTransformers): ts.CustomTransformers {
const beforeTs: Array<ts.TransformerFactory<ts.SourceFile>> = []; const beforeTs: Array<ts.TransformerFactory<ts.SourceFile>> = [];
const metadataTransforms: MetadataTransformer[] = []; const metadataTransforms: MetadataTransformer[] = [];
const flatModuleMetadataTransforms: MetadataTransformer[] = [];
if (this.options.enableResourceInlining) { if (this.options.enableResourceInlining) {
beforeTs.push(getInlineResourcesTransformFactory(this.tsProgram, this.hostAdapter)); beforeTs.push(getInlineResourcesTransformFactory(this.tsProgram, this.hostAdapter));
metadataTransforms.push(new InlineResourcesMetadataTransformer(this.hostAdapter)); const transformer = new InlineResourcesMetadataTransformer(this.hostAdapter);
metadataTransforms.push(transformer);
flatModuleMetadataTransforms.push(transformer);
} }
if (!this.options.disableExpressionLowering) { if (!this.options.disableExpressionLowering) {
@ -592,14 +597,18 @@ class AngularCompilerProgram implements Program {
// If we have partial modules, the cached metadata might be incorrect as it doesn't reflect // If we have partial modules, the cached metadata might be incorrect as it doesn't reflect
// the partial module transforms. // the partial module transforms.
metadataTransforms.push(new PartialModuleMetadataTransformer(partialModules)); const transformer = new PartialModuleMetadataTransformer(partialModules);
metadataTransforms.push(transformer);
flatModuleMetadataTransforms.push(transformer);
} }
if (stripDecorators) { if (stripDecorators) {
beforeTs.push(getDecoratorStripTransformerFactory( beforeTs.push(getDecoratorStripTransformerFactory(
stripDecorators, this.compiler.reflector, this.getTsProgram().getTypeChecker())); stripDecorators, this.compiler.reflector, this.getTsProgram().getTypeChecker()));
metadataTransforms.push( const transformer =
new StripDecoratorsMetadataTransformer(stripDecorators, this.compiler.reflector)); new StripDecoratorsMetadataTransformer(stripDecorators, this.compiler.reflector);
metadataTransforms.push(transformer);
flatModuleMetadataTransforms.push(transformer);
} }
if (customTransformers && customTransformers.beforeTs) { if (customTransformers && customTransformers.beforeTs) {
@ -608,6 +617,9 @@ class AngularCompilerProgram implements Program {
if (metadataTransforms.length > 0) { if (metadataTransforms.length > 0) {
this.metadataCache = this.createMetadataCache(metadataTransforms); this.metadataCache = this.createMetadataCache(metadataTransforms);
} }
if (flatModuleMetadataTransforms.length > 0) {
this.flatModuleMetadataCache = this.createMetadataCache(flatModuleMetadataTransforms);
}
const afterTs = customTransformers ? customTransformers.afterTs : undefined; const afterTs = customTransformers ? customTransformers.afterTs : undefined;
return {before: beforeTs, after: afterTs}; return {before: beforeTs, after: afterTs};
} }

View File

@ -1040,7 +1040,6 @@ describe('ngc transformer command-line', () => {
exports: [ exports: [
FlatComponent, FlatComponent,
], ],
providers: [{provide: 'test', useFactory: () => true}],
}) })
export class FlatModule { export class FlatModule {
}`); }`);
@ -1055,7 +1054,7 @@ describe('ngc transformer command-line', () => {
shouldExist('index.metadata.json'); shouldExist('index.metadata.json');
}); });
it('should downlevel flat module metadata', () => { it('should downlevel templates in flat module metadata', () => {
writeFlatModule('index.js'); writeFlatModule('index.js');
const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], errorSpy); const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], errorSpy);
@ -1066,7 +1065,7 @@ describe('ngc transformer command-line', () => {
const metadataPath = path.resolve(outDir, 'index.metadata.json'); const metadataPath = path.resolve(outDir, 'index.metadata.json');
const metadataSource = fs.readFileSync(metadataPath, 'utf8'); const metadataSource = fs.readFileSync(metadataPath, 'utf8');
expect(metadataSource).not.toContain('templateUrl'); expect(metadataSource).not.toContain('templateUrl');
expect(metadataSource).toContain('"useFactory":{"__symbolic":"reference","name":"ɵ0"}'); expect(metadataSource).toContain('<div>flat module component</div>');
}); });
describe('with tree example', () => { describe('with tree example', () => {