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
This commit is contained in:
JoostK
2021-12-09 01:11:30 +01:00
committed by Andrew Kushnir
parent 02b99f60f0
commit 73bbee2c0d
12 changed files with 37 additions and 94 deletions
@@ -104,7 +104,7 @@ export abstract class ChangeDetectorRef {
* Checks the change detector and its children, and throws if any changes are detected.
*
* Use in development mode to verify that running change detection doesn't introduce
* other changes.
* other changes. Calling it in production mode is a noop.
*/
abstract checkNoChanges(): void;
@@ -37,7 +37,8 @@ import {getLView, getSelectedIndex, getTView, isInCheckNoChangesMode, setSelecte
*/
export function ɵɵadvance(delta: number): void {
ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, isInCheckNoChangesMode());
selectIndexInternal(
getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
}
export function selectIndexInternal(
@@ -360,7 +360,7 @@ export function refreshView<T>(
enterView(lView);
// Check no changes mode is a dev only mode used to verify that bindings have not changed
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
const isInCheckNoChangesPass = isInCheckNoChangesMode();
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
try {
resetPreOrderHookFlags(lView);
@@ -481,10 +481,14 @@ export function refreshView<T>(
export function renderComponentOrTemplate<T>(
tView: TView, lView: LView, templateFn: ComponentTemplate<{}>|null, context: T) {
const rendererFactory = lView[RENDERER_FACTORY];
const normalExecutionPath = !isInCheckNoChangesMode();
// Check no changes mode is a dev only mode used to verify that bindings have not changed
// since they were assigned. We do not want to invoke renderer factory functions in that mode
// to avoid any possible side-effects.
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
const creationModeIsActive = isCreationMode(lView);
try {
if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) {
if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.begin) {
rendererFactory.begin();
}
if (creationModeIsActive) {
@@ -492,7 +496,7 @@ export function renderComponentOrTemplate<T>(
}
refreshView(tView, lView, templateFn, context);
} finally {
if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) {
if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.end) {
rendererFactory.end();
}
}
@@ -507,7 +511,7 @@ function executeTemplate<T>(
if (isUpdatePhase && lView.length > HEADER_OFFSET) {
// When we're updating, inherently select 0 so we don't
// have to generate that instruction for most update blocks.
selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode());
selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
}
const preHookType =
+15 -15
View File
@@ -7,7 +7,7 @@
*/
import {InjectFlags} from '../di/interface/injector';
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual} from '../util/assert';
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual, throwError} from '../util/assert';
import {assertLViewOrUndefined, assertTNodeForLView, assertTNodeForTView} from './assert';
import {DirectiveDef} from './interfaces/definition';
@@ -172,24 +172,23 @@ interface InstructionState {
* ```
*/
bindingsEnabled: boolean;
/**
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
*
* Necessary to support ChangeDetectorRef.checkNoChanges().
*
* checkNoChanges Runs only in devmode=true and verifies that no unintended changes exist in
* the change detector or its children.
*/
isInCheckNoChangesMode: boolean;
}
const instructionState: InstructionState = {
lFrame: createLFrame(null),
bindingsEnabled: true,
isInCheckNoChangesMode: false,
};
/**
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
*
* Necessary to support ChangeDetectorRef.checkNoChanges().
*
* The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
* changes exist in the change detector or its children.
*/
let _isInCheckNoChangesMode = false;
/**
* Returns true if the instruction state stack is empty.
*
@@ -336,12 +335,13 @@ export function getContextLView(): LView {
}
export function isInCheckNoChangesMode(): boolean {
// TODO(misko): remove this from the LView since it is ngDevMode=true mode only.
return instructionState.isInCheckNoChangesMode;
!ngDevMode && throwError('Must never be called in production mode');
return _isInCheckNoChangesMode;
}
export function setIsInCheckNoChangesMode(mode: boolean): void {
instructionState.isInCheckNoChangesMode = mode;
!ngDevMode && throwError('Must never be called in production mode');
_isInCheckNoChangesMode = mode;
}
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
+6 -2
View File
@@ -281,7 +281,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
* introduce other changes.
*/
checkNoChanges(): void {
checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
if (ngDevMode) {
checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
}
}
attachToViewContainerRef() {
@@ -318,7 +320,9 @@ export class RootViewRef<T> extends ViewRef<T> {
}
override checkNoChanges(): void {
checkNoChangesInRootView(this._view);
if (ngDevMode) {
checkNoChangesInRootView(this._view);
}
}
override get context(): T {
@@ -716,12 +716,6 @@
{
"name": "detachMovedView"
},
{
"name": "detectChangesInRootView"
},
{
"name": "detectChangesInternal"
},
{
"name": "diPublicInInjector"
},
@@ -998,9 +992,6 @@
{
"name": "isFunction"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isInlineTemplate"
},
@@ -1286,9 +1277,6 @@
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsInCheckNoChangesMode"
},
{
"name": "setSelectedIndex"
},
@@ -1388,4 +1376,4 @@
{
"name": "ɵɵproperty"
}
]
]
@@ -242,9 +242,6 @@
{
"name": "isCurrentTNodeParent"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isInlineTemplate"
},
@@ -737,12 +737,6 @@
{
"name": "detachView"
},
{
"name": "detectChangesInRootView"
},
{
"name": "detectChangesInternal"
},
{
"name": "diPublicInInjector"
},
@@ -1109,9 +1103,6 @@
{
"name": "isFunction"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isInlineTemplate"
},
@@ -1436,9 +1427,6 @@
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsInCheckNoChangesMode"
},
{
"name": "setSelectedIndex"
},
@@ -716,12 +716,6 @@
{
"name": "detachView"
},
{
"name": "detectChangesInRootView"
},
{
"name": "detectChangesInternal"
},
{
"name": "diPublicInInjector"
},
@@ -1073,9 +1067,6 @@
{
"name": "isFunction"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isInlineTemplate"
},
@@ -1418,9 +1409,6 @@
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsInCheckNoChangesMode"
},
{
"name": "setSelectedIndex"
},
@@ -1574,4 +1562,4 @@
{
"name": "ɵɵtext"
}
]
]
@@ -173,9 +173,6 @@
{
"name": "invertObject"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isProceduralRenderer"
},
@@ -251,4 +248,4 @@
{
"name": "ɵɵdefineComponent"
}
]
]
@@ -992,12 +992,6 @@
{
"name": "detachView"
},
{
"name": "detectChangesInRootView"
},
{
"name": "detectChangesInternal"
},
{
"name": "diPublicInInjector"
},
@@ -1415,9 +1409,6 @@
{
"name": "isImmediateMatch"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isInlineTemplate"
},
@@ -1760,9 +1751,6 @@
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsInCheckNoChangesMode"
},
{
"name": "setRouterState"
},
@@ -1967,4 +1955,4 @@
{
"name": "ɵɵtextInterpolate1"
}
]
]
@@ -305,12 +305,6 @@
{
"name": "detachView"
},
{
"name": "detectChangesInRootView"
},
{
"name": "detectChangesInternal"
},
{
"name": "diPublicInInjector"
},
@@ -548,9 +542,6 @@
{
"name": "isDirectiveHost"
},
{
"name": "isInCheckNoChangesMode"
},
{
"name": "isInlineTemplate"
},
@@ -746,9 +737,6 @@
{
"name": "setInputsFromAttrs"
},
{
"name": "setIsInCheckNoChangesMode"
},
{
"name": "setSelectedIndex"
},