Skip to content

Commit 8a60312

Browse files
crisbetoAndrewKushnir
authored andcommitted
refactor(core): track debugging information about deferred triggers (angular#59184)
Adds a field on the `TDeferBlockDetails` where we can track debugging information about the defer block. Also uses it to store text representation of the different triggers which can be shown to the dev tools. PR Close angular#59184
1 parent 1413677 commit 8a60312

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

packages/core/src/defer/instructions.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
getTDeferBlockDetails,
4949
setLDeferBlockDetails,
5050
setTDeferBlockDetails,
51+
trackTriggerForDebugging,
5152
} from './utils';
5253
import {DEHYDRATED_BLOCK_REGISTRY, DehydratedBlockRegistry} from './registry';
5354
import {assertIncrementalHydrationIsConfigured, assertSsrIdDefined} from '../hydration/utils';
@@ -119,6 +120,7 @@ export function ɵɵdefer(
119120
loadingPromise: null,
120121
providers: null,
121122
hydrateTriggers: null,
123+
debug: null,
122124
flags: flags ?? TDeferDetailsFlags.Default,
123125
};
124126
enableTimerScheduling?.(tView, tDetails, placeholderConfigIndex, loadingConfigIndex);
@@ -187,6 +189,10 @@ export function ɵɵdeferWhen(rawValue: unknown) {
187189
const lView = getLView();
188190
const tNode = getSelectedTNode();
189191

192+
if (ngDevMode) {
193+
trackTriggerForDebugging(lView[TVIEW], tNode, 'when <expression>');
194+
}
195+
190196
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
191197

192198
const bindingIndex = nextBindingIndex();
@@ -220,6 +226,10 @@ export function ɵɵdeferPrefetchWhen(rawValue: unknown) {
220226
const lView = getLView();
221227
const tNode = getSelectedTNode();
222228

229+
if (ngDevMode) {
230+
trackTriggerForDebugging(lView[TVIEW], tNode, 'prefetch when <expression>');
231+
}
232+
223233
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
224234

225235
const bindingIndex = nextBindingIndex();
@@ -249,6 +259,10 @@ export function ɵɵdeferHydrateWhen(rawValue: unknown) {
249259
const lView = getLView();
250260
const tNode = getSelectedTNode();
251261

262+
if (ngDevMode) {
263+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate when <expression>');
264+
}
265+
252266
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
253267

254268
// TODO(incremental-hydration): audit all defer instructions to reduce unnecessary work by
@@ -291,6 +305,10 @@ export function ɵɵdeferHydrateNever() {
291305
const lView = getLView();
292306
const tNode = getCurrentTNode()!;
293307

308+
if (ngDevMode) {
309+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate never');
310+
}
311+
294312
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
295313

296314
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);
@@ -310,6 +328,10 @@ export function ɵɵdeferOnIdle() {
310328
const lView = getLView();
311329
const tNode = getCurrentTNode()!;
312330

331+
if (ngDevMode) {
332+
trackTriggerForDebugging(lView[TVIEW], tNode, 'on idle');
333+
}
334+
313335
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
314336

315337
scheduleDelayedTrigger(onIdle);
@@ -323,6 +345,10 @@ export function ɵɵdeferPrefetchOnIdle() {
323345
const lView = getLView();
324346
const tNode = getCurrentTNode()!;
325347

348+
if (ngDevMode) {
349+
trackTriggerForDebugging(lView[TVIEW], tNode, 'prefetch on idle');
350+
}
351+
326352
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
327353

328354
scheduleDelayedPrefetching(onIdle, DeferBlockTrigger.Idle);
@@ -336,6 +362,10 @@ export function ɵɵdeferHydrateOnIdle() {
336362
const lView = getLView();
337363
const tNode = getCurrentTNode()!;
338364

365+
if (ngDevMode) {
366+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate on idle');
367+
}
368+
339369
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
340370

341371
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);
@@ -357,6 +387,10 @@ export function ɵɵdeferOnImmediate() {
357387
const lView = getLView();
358388
const tNode = getCurrentTNode()!;
359389

390+
if (ngDevMode) {
391+
trackTriggerForDebugging(lView[TVIEW], tNode, 'on immediate');
392+
}
393+
360394
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
361395

362396
// Render placeholder block only if loading template is not present and we're on
@@ -377,6 +411,10 @@ export function ɵɵdeferPrefetchOnImmediate() {
377411
const lView = getLView();
378412
const tNode = getCurrentTNode()!;
379413

414+
if (ngDevMode) {
415+
trackTriggerForDebugging(lView[TVIEW], tNode, 'prefetch on immediate');
416+
}
417+
380418
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
381419

382420
const tView = lView[TVIEW];
@@ -395,6 +433,10 @@ export function ɵɵdeferHydrateOnImmediate() {
395433
const lView = getLView();
396434
const tNode = getCurrentTNode()!;
397435

436+
if (ngDevMode) {
437+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate on immediate');
438+
}
439+
398440
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
399441

400442
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);
@@ -419,6 +461,10 @@ export function ɵɵdeferOnTimer(delay: number) {
419461
const lView = getLView();
420462
const tNode = getCurrentTNode()!;
421463

464+
if (ngDevMode) {
465+
trackTriggerForDebugging(lView[TVIEW], tNode, `on timer(${delay}ms)`);
466+
}
467+
422468
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
423469

424470
scheduleDelayedTrigger(onTimer(delay));
@@ -433,6 +479,10 @@ export function ɵɵdeferPrefetchOnTimer(delay: number) {
433479
const lView = getLView();
434480
const tNode = getCurrentTNode()!;
435481

482+
if (ngDevMode) {
483+
trackTriggerForDebugging(lView[TVIEW], tNode, `prefetch on timer(${delay}ms)`);
484+
}
485+
436486
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
437487

438488
scheduleDelayedPrefetching(onTimer(delay), DeferBlockTrigger.Timer);
@@ -447,6 +497,10 @@ export function ɵɵdeferHydrateOnTimer(delay: number) {
447497
const lView = getLView();
448498
const tNode = getCurrentTNode()!;
449499

500+
if (ngDevMode) {
501+
trackTriggerForDebugging(lView[TVIEW], tNode, `hydrate on timer(${delay}ms)`);
502+
}
503+
450504
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
451505

452506
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);
@@ -470,6 +524,14 @@ export function ɵɵdeferOnHover(triggerIndex: number, walkUpTimes?: number) {
470524
const lView = getLView();
471525
const tNode = getCurrentTNode()!;
472526

527+
if (ngDevMode) {
528+
trackTriggerForDebugging(
529+
lView[TVIEW],
530+
tNode,
531+
`on hover${walkUpTimes === -1 ? '' : '(<target>)'}`,
532+
);
533+
}
534+
473535
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
474536

475537
renderPlaceholder(lView, tNode);
@@ -498,6 +560,14 @@ export function ɵɵdeferPrefetchOnHover(triggerIndex: number, walkUpTimes?: num
498560
const lView = getLView();
499561
const tNode = getCurrentTNode()!;
500562

563+
if (ngDevMode) {
564+
trackTriggerForDebugging(
565+
lView[TVIEW],
566+
tNode,
567+
`prefetch on hover${walkUpTimes === -1 ? '' : '(<target>)'}`,
568+
);
569+
}
570+
501571
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
502572

503573
const tView = lView[TVIEW];
@@ -524,6 +594,10 @@ export function ɵɵdeferHydrateOnHover() {
524594
const lView = getLView();
525595
const tNode = getCurrentTNode()!;
526596

597+
if (ngDevMode) {
598+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate on hover');
599+
}
600+
527601
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
528602

529603
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);
@@ -547,6 +621,14 @@ export function ɵɵdeferOnInteraction(triggerIndex: number, walkUpTimes?: numbe
547621
const lView = getLView();
548622
const tNode = getCurrentTNode()!;
549623

624+
if (ngDevMode) {
625+
trackTriggerForDebugging(
626+
lView[TVIEW],
627+
tNode,
628+
`on interaction${walkUpTimes === -1 ? '' : '(<target>)'}`,
629+
);
630+
}
631+
550632
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
551633

552634
renderPlaceholder(lView, tNode);
@@ -575,6 +657,14 @@ export function ɵɵdeferPrefetchOnInteraction(triggerIndex: number, walkUpTimes
575657
const lView = getLView();
576658
const tNode = getCurrentTNode()!;
577659

660+
if (ngDevMode) {
661+
trackTriggerForDebugging(
662+
lView[TVIEW],
663+
tNode,
664+
`prefetch on interaction${walkUpTimes === -1 ? '' : '(<target>)'}`,
665+
);
666+
}
667+
578668
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
579669

580670
const tView = lView[TVIEW];
@@ -601,6 +691,10 @@ export function ɵɵdeferHydrateOnInteraction() {
601691
const lView = getLView();
602692
const tNode = getCurrentTNode()!;
603693

694+
if (ngDevMode) {
695+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate on interaction');
696+
}
697+
604698
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
605699

606700
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);
@@ -624,6 +718,14 @@ export function ɵɵdeferOnViewport(triggerIndex: number, walkUpTimes?: number)
624718
const lView = getLView();
625719
const tNode = getCurrentTNode()!;
626720

721+
if (ngDevMode) {
722+
trackTriggerForDebugging(
723+
lView[TVIEW],
724+
tNode,
725+
`on viewport${walkUpTimes === -1 ? '' : '(<target>)'}`,
726+
);
727+
}
728+
627729
if (!shouldAttachTrigger(TriggerType.Regular, lView, tNode)) return;
628730

629731
renderPlaceholder(lView, tNode);
@@ -652,6 +754,14 @@ export function ɵɵdeferPrefetchOnViewport(triggerIndex: number, walkUpTimes?:
652754
const lView = getLView();
653755
const tNode = getCurrentTNode()!;
654756

757+
if (ngDevMode) {
758+
trackTriggerForDebugging(
759+
lView[TVIEW],
760+
tNode,
761+
`prefetch on viewport${walkUpTimes === -1 ? '' : '(<target>)'}`,
762+
);
763+
}
764+
655765
if (!shouldAttachTrigger(TriggerType.Prefetch, lView, tNode)) return;
656766

657767
const tView = lView[TVIEW];
@@ -678,6 +788,10 @@ export function ɵɵdeferHydrateOnViewport() {
678788
const lView = getLView();
679789
const tNode = getCurrentTNode()!;
680790

791+
if (ngDevMode) {
792+
trackTriggerForDebugging(lView[TVIEW], tNode, 'hydrate on viewport');
793+
}
794+
681795
if (!shouldAttachTrigger(TriggerType.Hydrate, lView, tNode)) return;
682796

683797
const hydrateTriggers = getHydrateTriggers(getTView(), tNode);

packages/core/src/defer/interfaces.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ export interface TDeferBlockDetails {
146146
* placed into the `TDeferDetails` at runtime).
147147
*/
148148
flags: TDeferDetailsFlags;
149+
150+
/**
151+
* Tracks debugging information about the deferred block.
152+
*/
153+
debug: {
154+
/** Text representations of the block's triggers. */
155+
triggers?: Set<string>;
156+
} | null;
149157
}
150158

151159
/**

packages/core/src/defer/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,16 @@ export function isDeferBlock(tView: TView, tNode: TNode): boolean {
181181
}
182182
return !!tDetails && isTDeferBlockDetails(tDetails);
183183
}
184+
185+
/**
186+
* Tracks debugging information about a trigger.
187+
* @param tView TView in which the trigger is declared.
188+
* @param tNode TNode on which the trigger is declared.
189+
* @param textRepresentation Text representation of the trigger to be used for debugging purposes.
190+
*/
191+
export function trackTriggerForDebugging(tView: TView, tNode: TNode, textRepresentation: string) {
192+
const tDetails = getTDeferBlockDetails(tView, tNode);
193+
tDetails.debug ??= {};
194+
tDetails.debug.triggers ??= new Set();
195+
tDetails.debug.triggers.add(textRepresentation);
196+
}

0 commit comments

Comments
 (0)