Skip to content

Commit 4a2df56

Browse files
thePunderWomanAndrewKushnir
authored andcommitted
refactor(core): add skipped defer blocks count to ngDevMode (angular#59188)
This adds the skipped defer blocks to the counts in ngDevMode and the logged hydration information. PR Close angular#59188
1 parent 1f4ff2f commit 4a2df56

File tree

8 files changed

+1245
-1018
lines changed

8 files changed

+1245
-1018
lines changed

packages/core/src/hydration/annotate.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,12 @@ function serializeLContainer(
391391
// If this is a defer block, serialize extra info.
392392
if (isDeferBlock(lView[TVIEW], tNode)) {
393393
const lDetails = getLDeferBlockDetails(lView, tNode);
394+
const tDetails = getTDeferBlockDetails(lView[TVIEW], tNode);
394395

395-
if (context.isIncrementalHydrationEnabled) {
396+
if (context.isIncrementalHydrationEnabled && tDetails.hydrateTriggers !== null) {
396397
const deferBlockId = `d${context.deferBlocks.size}`;
397398

398-
const tDetails = getTDeferBlockDetails(lView[TVIEW], tNode);
399-
if (tDetails.hydrateTriggers?.has(DeferBlockTrigger.Never)) {
399+
if (tDetails.hydrateTriggers.has(DeferBlockTrigger.Never)) {
400400
isHydrateNeverBlock = true;
401401
}
402402

@@ -408,9 +408,13 @@ function serializeLContainer(
408408
[DEFER_PARENT_BLOCK_ID]: parentDeferBlockId,
409409
[NUM_ROOT_NODES]: rootNodes.length,
410410
[DEFER_BLOCK_STATE]: lDetails[CURRENT_DEFER_BLOCK_STATE],
411-
[DEFER_HYDRATE_TRIGGERS]: serializeHydrateTriggers(tDetails.hydrateTriggers),
412411
};
413412

413+
const serializedTriggers = serializeHydrateTriggers(tDetails.hydrateTriggers);
414+
if (serializedTriggers.length > 0) {
415+
deferBlockInfo[DEFER_HYDRATE_TRIGGERS] = serializedTriggers;
416+
}
417+
414418
context.deferBlocks.set(deferBlockId, deferBlockInfo);
415419

416420
const node = unwrapRNode(lContainer);
@@ -471,11 +475,8 @@ function serializeLContainer(
471475
}
472476

473477
function serializeHydrateTriggers(
474-
triggerMap: Map<DeferBlockTrigger, HydrateTriggerDetails | null> | null,
475-
): (DeferBlockTrigger | SerializedTriggerDetails)[] | null {
476-
if (triggerMap === null) {
477-
return null;
478-
}
478+
triggerMap: Map<DeferBlockTrigger, HydrateTriggerDetails | null>,
479+
): (DeferBlockTrigger | SerializedTriggerDetails)[] {
479480
const serializableDeferBlockTrigger = new Set<DeferBlockTrigger>([
480481
DeferBlockTrigger.Idle,
481482
DeferBlockTrigger.Immediate,

packages/core/src/hydration/api.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ import {
4444
} from './tokens';
4545
import {
4646
appendDeferBlocksToJSActionMap,
47+
countBlocksSkippedByHydration,
4748
enableRetrieveDeferBlockDataImpl,
4849
enableRetrieveHydrationInfoImpl,
50+
isIncrementalHydrationEnabled,
4951
NGH_DATA_KEY,
5052
processBlockData,
5153
SSR_CONTENT_INTEGRITY_MARKER,
@@ -143,6 +145,9 @@ function printHydrationStats(injector: Injector) {
143145
`Angular hydrated ${ngDevMode!.hydratedComponents} component(s) ` +
144146
`and ${ngDevMode!.hydratedNodes} node(s), ` +
145147
`${ngDevMode!.componentsSkippedHydration} component(s) were skipped. ` +
148+
(isIncrementalHydrationEnabled(injector)
149+
? `${ngDevMode!.deferBlocksWithIncrementalHydration} defer block(s) were configured to use incremental hydration. `
150+
: '') +
146151
`Learn more at https://angular.dev/guide/hydration.`;
147152
// tslint:disable-next-line:no-console
148153
console.log(message);
@@ -282,6 +287,7 @@ export function withDomHydration(): EnvironmentProviders {
282287
whenStableWithTimeout(appRef, injector).then(() => {
283288
cleanupDehydratedViews(appRef);
284289
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
290+
countBlocksSkippedByHydration(injector);
285291
printHydrationStats(injector);
286292
}
287293
});

packages/core/src/hydration/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export interface SerializedDeferBlock {
177177
* The list of triggers that exist for incremental hydration, based on the
178178
* `Trigger` enum.
179179
*/
180-
[DEFER_HYDRATE_TRIGGERS]: (DeferBlockTrigger | SerializedTriggerDetails)[] | null;
180+
[DEFER_HYDRATE_TRIGGERS]?: (DeferBlockTrigger | SerializedTriggerDetails)[];
181181
}
182182

183183
export interface SerializedTriggerDetails {

packages/core/src/hydration/utils.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ export function retrieveHydrationInfoImpl(
135135
const remainingNgh = isRootView ? componentViewNgh : rootNgh;
136136

137137
let data: SerializedView = {};
138-
let nghDeferData: {[key: string]: SerializedDeferBlock} | undefined;
139138
// An element might have an empty `ngh` attribute value (e.g. `<comp ngh="" />`),
140139
// which means that no special annotations are required. Do not attempt to read
141140
// from the TransferState in this case.
@@ -144,8 +143,6 @@ export function retrieveHydrationInfoImpl(
144143
if (transferState !== null) {
145144
const nghData = transferState.get(NGH_DATA_KEY, []);
146145

147-
nghDeferData = transferState.get(NGH_DEFER_BLOCKS_KEY, {});
148-
149146
// The nghAttrValue is always a number referencing an index
150147
// in the hydration TransferState data.
151148
data = nghData[Number(nghAttrValue)];
@@ -344,6 +341,14 @@ export function markRNodeAsSkippedByHydration(node: RNode) {
344341
ngDevMode.componentsSkippedHydration++;
345342
}
346343

344+
export function countBlocksSkippedByHydration(injector: Injector) {
345+
const transferState = injector.get(TransferState);
346+
const nghDeferData = transferState.get(NGH_DEFER_BLOCKS_KEY, {});
347+
if (ngDevMode) {
348+
ngDevMode.deferBlocksWithIncrementalHydration = Object.keys(nghDeferData).length;
349+
}
350+
}
351+
347352
export function markRNodeAsHavingHydrationMismatch(
348353
node: RNode,
349354
expectedNodeDetails: string | null = null,

packages/core/src/util/ng_dev_mode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ declare global {
5454
dehydratedViewsRemoved: number;
5555
dehydratedViewsCleanupRuns: number;
5656
componentsSkippedHydration: number;
57+
deferBlocksWithIncrementalHydration: number;
5758
}
5859
}
5960

@@ -88,6 +89,7 @@ export function ngDevModeResetPerfCounters(): NgDevModePerfCounters {
8889
dehydratedViewsRemoved: 0,
8990
dehydratedViewsCleanupRuns: 0,
9091
componentsSkippedHydration: 0,
92+
deferBlocksWithIncrementalHydration: 0,
9193
};
9294

9395
// Make sure to refer to ngDevMode as ['ngDevMode'] for closure.

packages/platform-server/test/full_app_hydration_spec.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,14 @@ import {
8282
withNoopErrorHandler,
8383
verifyEmptyConsole,
8484
clearConsole,
85+
resetNgDevModeCounters,
8586
} from './hydration_utils';
8687

8788
import {CLIENT_RENDER_MODE_FLAG} from '@angular/core/src/hydration/api';
8889

8990
describe('platform-server full application hydration integration', () => {
9091
beforeEach(() => {
91-
if (typeof ngDevMode === 'object') {
92-
// Reset all ngDevMode counters.
93-
for (const metric of Object.keys(ngDevMode!)) {
94-
const currentValue = (ngDevMode as unknown as {[key: string]: number | boolean})[metric];
95-
if (typeof currentValue === 'number') {
96-
// Rest only numeric values, which represent counters.
97-
(ngDevMode as unknown as {[key: string]: number | boolean})[metric] = 0;
98-
}
99-
}
100-
}
92+
resetNgDevModeCounters();
10193
});
10294

10395
afterEach(() => {

packages/platform-server/test/hydration_utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,17 @@ export function clearConsole(appRef: ApplicationRef) {
286286
const console = appRef.injector.get(Console) as DebugConsole;
287287
console.logs = [];
288288
}
289+
290+
// Clears all the counts in ngDevMode
291+
export function resetNgDevModeCounters() {
292+
if (typeof ngDevMode === 'object') {
293+
// Reset all ngDevMode counters.
294+
for (const metric of Object.keys(ngDevMode!)) {
295+
const currentValue = (ngDevMode as unknown as {[key: string]: number | boolean})[metric];
296+
if (typeof currentValue === 'number') {
297+
// Rest only numeric values, which represent counters.
298+
(ngDevMode as unknown as {[key: string]: number | boolean})[metric] = 0;
299+
}
300+
}
301+
}
302+
}

0 commit comments

Comments
 (0)