Skip to content

Commit 73bbee2

Browse files
JoostKAndrewKushnir
authored andcommitted
perf(core): allow checkNoChanges mode to be tree-shaken in production (#45936)
This commit guards all logic that exists for the `checkNoChanges` mode with `ngDevMode` checks such that the logic can be tree-shaken. PR Close #45936
1 parent 02b99f6 commit 73bbee2

File tree

12 files changed

+37
-94
lines changed

12 files changed

+37
-94
lines changed

packages/core/src/change_detection/change_detector_ref.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export abstract class ChangeDetectorRef {
104104
* Checks the change detector and its children, and throws if any changes are detected.
105105
*
106106
* Use in development mode to verify that running change detection doesn't introduce
107-
* other changes.
107+
* other changes. Calling it in production mode is a noop.
108108
*/
109109
abstract checkNoChanges(): void;
110110

packages/core/src/render3/instructions/advance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ import {getLView, getSelectedIndex, getTView, isInCheckNoChangesMode, setSelecte
3737
*/
3838
export function ɵɵadvance(delta: number): void {
3939
ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
40-
selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, isInCheckNoChangesMode());
40+
selectIndexInternal(
41+
getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
4142
}
4243

4344
export function selectIndexInternal(

packages/core/src/render3/instructions/shared.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ export function refreshView<T>(
360360
enterView(lView);
361361
// Check no changes mode is a dev only mode used to verify that bindings have not changed
362362
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
363-
const isInCheckNoChangesPass = isInCheckNoChangesMode();
363+
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
364364
try {
365365
resetPreOrderHookFlags(lView);
366366

@@ -481,18 +481,22 @@ export function refreshView<T>(
481481
export function renderComponentOrTemplate<T>(
482482
tView: TView, lView: LView, templateFn: ComponentTemplate<{}>|null, context: T) {
483483
const rendererFactory = lView[RENDERER_FACTORY];
484-
const normalExecutionPath = !isInCheckNoChangesMode();
484+
485+
// Check no changes mode is a dev only mode used to verify that bindings have not changed
486+
// since they were assigned. We do not want to invoke renderer factory functions in that mode
487+
// to avoid any possible side-effects.
488+
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
485489
const creationModeIsActive = isCreationMode(lView);
486490
try {
487-
if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) {
491+
if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.begin) {
488492
rendererFactory.begin();
489493
}
490494
if (creationModeIsActive) {
491495
renderView(tView, lView, context);
492496
}
493497
refreshView(tView, lView, templateFn, context);
494498
} finally {
495-
if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) {
499+
if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.end) {
496500
rendererFactory.end();
497501
}
498502
}
@@ -507,7 +511,7 @@ function executeTemplate<T>(
507511
if (isUpdatePhase && lView.length > HEADER_OFFSET) {
508512
// When we're updating, inherently select 0 so we don't
509513
// have to generate that instruction for most update blocks.
510-
selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode());
514+
selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
511515
}
512516

513517
const preHookType =

packages/core/src/render3/state.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {InjectFlags} from '../di/interface/injector';
10-
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual} from '../util/assert';
10+
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual, throwError} from '../util/assert';
1111

1212
import {assertLViewOrUndefined, assertTNodeForLView, assertTNodeForTView} from './assert';
1313
import {DirectiveDef} from './interfaces/definition';
@@ -172,24 +172,23 @@ interface InstructionState {
172172
* ```
173173
*/
174174
bindingsEnabled: boolean;
175-
176-
/**
177-
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
178-
*
179-
* Necessary to support ChangeDetectorRef.checkNoChanges().
180-
*
181-
* checkNoChanges Runs only in devmode=true and verifies that no unintended changes exist in
182-
* the change detector or its children.
183-
*/
184-
isInCheckNoChangesMode: boolean;
185175
}
186176

187177
const instructionState: InstructionState = {
188178
lFrame: createLFrame(null),
189179
bindingsEnabled: true,
190-
isInCheckNoChangesMode: false,
191180
};
192181

182+
/**
183+
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
184+
*
185+
* Necessary to support ChangeDetectorRef.checkNoChanges().
186+
*
187+
* The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
188+
* changes exist in the change detector or its children.
189+
*/
190+
let _isInCheckNoChangesMode = false;
191+
193192
/**
194193
* Returns true if the instruction state stack is empty.
195194
*
@@ -336,12 +335,13 @@ export function getContextLView(): LView {
336335
}
337336

338337
export function isInCheckNoChangesMode(): boolean {
339-
// TODO(misko): remove this from the LView since it is ngDevMode=true mode only.
340-
return instructionState.isInCheckNoChangesMode;
338+
!ngDevMode && throwError('Must never be called in production mode');
339+
return _isInCheckNoChangesMode;
341340
}
342341

343342
export function setIsInCheckNoChangesMode(mode: boolean): void {
344-
instructionState.isInCheckNoChangesMode = mode;
343+
!ngDevMode && throwError('Must never be called in production mode');
344+
_isInCheckNoChangesMode = mode;
345345
}
346346

347347
// top level variables should not be exported for performance reasons (PERF_NOTES.md)

packages/core/src/render3/view_ref.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
281281
* introduce other changes.
282282
*/
283283
checkNoChanges(): void {
284-
checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
284+
if (ngDevMode) {
285+
checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
286+
}
285287
}
286288

287289
attachToViewContainerRef() {
@@ -318,7 +320,9 @@ export class RootViewRef<T> extends ViewRef<T> {
318320
}
319321

320322
override checkNoChanges(): void {
321-
checkNoChangesInRootView(this._view);
323+
if (ngDevMode) {
324+
checkNoChangesInRootView(this._view);
325+
}
322326
}
323327

324328
override get context(): T {

packages/core/test/bundling/animations/bundle.golden_symbols.json

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -716,12 +716,6 @@
716716
{
717717
"name": "detachMovedView"
718718
},
719-
{
720-
"name": "detectChangesInRootView"
721-
},
722-
{
723-
"name": "detectChangesInternal"
724-
},
725719
{
726720
"name": "diPublicInInjector"
727721
},
@@ -998,9 +992,6 @@
998992
{
999993
"name": "isFunction"
1000994
},
1001-
{
1002-
"name": "isInCheckNoChangesMode"
1003-
},
1004995
{
1005996
"name": "isInlineTemplate"
1006997
},
@@ -1286,9 +1277,6 @@
12861277
{
12871278
"name": "setInputsFromAttrs"
12881279
},
1289-
{
1290-
"name": "setIsInCheckNoChangesMode"
1291-
},
12921280
{
12931281
"name": "setSelectedIndex"
12941282
},
@@ -1388,4 +1376,4 @@
13881376
{
13891377
"name": "ɵɵproperty"
13901378
}
1391-
]
1379+
]

packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,6 @@
242242
{
243243
"name": "isCurrentTNodeParent"
244244
},
245-
{
246-
"name": "isInCheckNoChangesMode"
247-
},
248245
{
249246
"name": "isInlineTemplate"
250247
},

packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -737,12 +737,6 @@
737737
{
738738
"name": "detachView"
739739
},
740-
{
741-
"name": "detectChangesInRootView"
742-
},
743-
{
744-
"name": "detectChangesInternal"
745-
},
746740
{
747741
"name": "diPublicInInjector"
748742
},
@@ -1109,9 +1103,6 @@
11091103
{
11101104
"name": "isFunction"
11111105
},
1112-
{
1113-
"name": "isInCheckNoChangesMode"
1114-
},
11151106
{
11161107
"name": "isInlineTemplate"
11171108
},
@@ -1436,9 +1427,6 @@
14361427
{
14371428
"name": "setInputsFromAttrs"
14381429
},
1439-
{
1440-
"name": "setIsInCheckNoChangesMode"
1441-
},
14421430
{
14431431
"name": "setSelectedIndex"
14441432
},

packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -716,12 +716,6 @@
716716
{
717717
"name": "detachView"
718718
},
719-
{
720-
"name": "detectChangesInRootView"
721-
},
722-
{
723-
"name": "detectChangesInternal"
724-
},
725719
{
726720
"name": "diPublicInInjector"
727721
},
@@ -1073,9 +1067,6 @@
10731067
{
10741068
"name": "isFunction"
10751069
},
1076-
{
1077-
"name": "isInCheckNoChangesMode"
1078-
},
10791070
{
10801071
"name": "isInlineTemplate"
10811072
},
@@ -1418,9 +1409,6 @@
14181409
{
14191410
"name": "setInputsFromAttrs"
14201411
},
1421-
{
1422-
"name": "setIsInCheckNoChangesMode"
1423-
},
14241412
{
14251413
"name": "setSelectedIndex"
14261414
},
@@ -1574,4 +1562,4 @@
15741562
{
15751563
"name": "ɵɵtext"
15761564
}
1577-
]
1565+
]

packages/core/test/bundling/hello_world/bundle.golden_symbols.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,6 @@
173173
{
174174
"name": "invertObject"
175175
},
176-
{
177-
"name": "isInCheckNoChangesMode"
178-
},
179176
{
180177
"name": "isProceduralRenderer"
181178
},
@@ -251,4 +248,4 @@
251248
{
252249
"name": "ɵɵdefineComponent"
253250
}
254-
]
251+
]

0 commit comments

Comments
 (0)