Skip to content

Commit 377a7ab

Browse files
pmvalddylhunn
authored andcommitted
fix(compiler-cli): bypass static resolving of the component's changeDetection field in local compilation mode (#51848)
Currently the field changeDetection undergoes some static analysis to check if it is `ChangeDetectionStrategy` enum. Such static check fails in local compilation mode in g3 as the symbol cannot be resolved. So in local compilation mode we bypass such resolving and just write the expression as is into the component definition. PR Close #51848
1 parent dcaad16 commit 377a7ab

File tree

6 files changed

+53
-13
lines changed

6 files changed

+53
-13
lines changed

packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,14 @@ export class ComponentDecoratorHandler implements
235235
const encapsulation: number =
236236
resolveEnumValue(this.evaluator, component, 'encapsulation', 'ViewEncapsulation') ??
237237
ViewEncapsulation.Emulated;
238-
const changeDetection: number|null =
239-
resolveEnumValue(this.evaluator, component, 'changeDetection', 'ChangeDetectionStrategy');
238+
239+
let changeDetection: number|Expression|null = null;
240+
if (this.compilationMode !== CompilationMode.LOCAL) {
241+
changeDetection =
242+
resolveEnumValue(this.evaluator, component, 'changeDetection', 'ChangeDetectionStrategy');
243+
} else if (component.has('changeDetection')) {
244+
changeDetection = new WrappedNodeExpr(component.get('changeDetection')!);
245+
}
240246

241247
let animations: Expression|null = null;
242248
let animationTriggerNames: AnimationTriggerNames|null = null;
@@ -459,6 +465,7 @@ export class ComponentDecoratorHandler implements
459465
ngContentSelectors: template.ngContentSelectors,
460466
},
461467
encapsulation,
468+
changeDetection,
462469
interpolation: template.interpolationConfig ?? DEFAULT_INTERPOLATION_CONFIG,
463470
styles,
464471

@@ -494,9 +501,7 @@ export class ComponentDecoratorHandler implements
494501
},
495502
diagnostics,
496503
};
497-
if (changeDetection !== null) {
498-
output.analysis!.meta.changeDetection = changeDetection;
499-
}
504+
500505
return output;
501506
}
502507

packages/compiler-cli/test/ngtsc/local_compilation_spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,27 @@ runInEachFileSystem(() => {
345345
});
346346
});
347347

348+
describe('component fields', () => {
349+
it('should place the changeDetection as it is into the component def', () => {
350+
env.write('test.ts', `
351+
import {Component} from '@angular/core';
352+
import {SomeWeirdThing} from 'some-where';
353+
354+
@Component({
355+
changeDetection: SomeWeirdThing,
356+
template: '<span>Hello world!</span>',
357+
})
358+
export class MainComponent {
359+
}
360+
`);
361+
362+
env.driveMain();
363+
const jsContents = env.getContents('test.js');
364+
365+
expect(jsContents).toContain('changeDetection: SomeWeirdThing');
366+
});
367+
});
368+
348369
describe('constructor injection', () => {
349370
it('should include injector types with all possible import/injection styles into component factory',
350371
() => {

packages/compiler/src/jit_compiler_facade.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export class CompilerFacadeImpl implements CompilerFacade {
208208
styles: [...facade.styles, ...template.styles],
209209
encapsulation: facade.encapsulation,
210210
interpolation,
211-
changeDetection: facade.changeDetection,
211+
changeDetection: facade.changeDetection ?? null,
212212
animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null,
213213
viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) :
214214
null,

packages/compiler/src/render3/partial/component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ export function createComponentDefinitionMap(
8282
definitionMap.set('viewProviders', meta.viewProviders);
8383
definitionMap.set('animations', meta.animations);
8484

85-
if (meta.changeDetection !== undefined) {
85+
if (meta.changeDetection !== null) {
86+
if (typeof meta.changeDetection === 'object') {
87+
throw new Error('Impossible state! Change detection flag is not resolved!');
88+
}
89+
8690
definitionMap.set(
8791
'changeDetection',
8892
o.importExpr(R3.ChangeDetectionStrategy)

packages/compiler/src/render3/view/api.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,12 @@ export interface R3ComponentMetadata<DeclarationT extends R3TemplateDependency>
292292

293293
/**
294294
* Strategy used for detecting changes in the component.
295+
*
296+
* In global compilation mode the value is ChangeDetectionStrategy if available as it is
297+
* statically resolved during analysis phase. Whereas in local compilation mode the value is the
298+
* expression as appears in the decorator.
295299
*/
296-
changeDetection?: ChangeDetectionStrategy;
300+
changeDetection: ChangeDetectionStrategy|o.Expression|null;
297301

298302
/**
299303
* The imports expression as appears on the component decorate for standalone component. This

packages/compiler/src/render3/view/compiler.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,6 @@ export function compileComponentFromMetadata(
185185
const templateTypeName = meta.name;
186186
const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
187187

188-
const changeDetection = meta.changeDetection;
189-
190188
// Template compilation is currently conditional as we're in the process of rewriting it.
191189
if (!USE_TEMPLATE_PIPELINE) {
192190
// This is the main path currently used in compilation, which compiles the template with the
@@ -313,9 +311,17 @@ export function compileComponentFromMetadata(
313311
'data', o.literalMap([{key: 'animation', value: meta.animations, quoted: false}]));
314312
}
315313

316-
// Only set the change detection flag if it's defined and it's not the default.
317-
if (changeDetection != null && changeDetection !== core.ChangeDetectionStrategy.Default) {
318-
definitionMap.set('changeDetection', o.literal(changeDetection));
314+
// Setting change detection flag
315+
if (meta.changeDetection !== null) {
316+
if (typeof meta.changeDetection === 'number' &&
317+
meta.changeDetection !== core.ChangeDetectionStrategy.Default) {
318+
// changeDetection is resolved during analysis. Only set it if not the default.
319+
definitionMap.set('changeDetection', o.literal(meta.changeDetection));
320+
} else if (typeof meta.changeDetection === 'object') {
321+
// changeDetection is not resolved during analysis (e.g., we are in local compilation mode).
322+
// So place it as is.
323+
definitionMap.set('changeDetection', meta.changeDetection);
324+
}
319325
}
320326

321327
const expression =

0 commit comments

Comments
 (0)