From d760cbe71b28abeefdbde74a81ac942fcb3eb870 Mon Sep 17 00:00:00 2001 From: Jessica Janiuk Date: Tue, 15 Oct 2024 10:37:08 -0400 Subject: [PATCH] refactor(core): Update interfaces for handling defer completion (#58206) This adds properties to the LDeferBlockDetails and ensures the completion functions exist for future incremental hydration use cases. PR Close #58206 --- packages/core/src/defer/instructions.ts | 28 +++++++++++++++++++ packages/core/src/defer/interfaces.ts | 24 ++++++++++++++++ .../bundling/defer/bundle.golden_symbols.json | 3 ++ 3 files changed, 55 insertions(+) diff --git a/packages/core/src/defer/instructions.ts b/packages/core/src/defer/instructions.ts index 31e8fea1ccf..b6c978656da 100644 --- a/packages/core/src/defer/instructions.ts +++ b/packages/core/src/defer/instructions.ts @@ -73,6 +73,7 @@ import { LDeferBlockDetails, LOADING_AFTER_CLEANUP_FN, NEXT_DEFER_BLOCK_STATE, + ON_COMPLETE_FNS, STATE_IS_FROZEN_UNTIL, TDeferBlockDetails, TriggerType, @@ -230,6 +231,10 @@ export function ɵɵdefer( null, // LOADING_AFTER_CLEANUP_FN null, // TRIGGER_CLEANUP_FNS null, // PREFETCH_TRIGGER_CLEANUP_FNS + null, // UNIQUE_SSR_ID + null, // SSR_STATE + null, // ON_COMPLETE_FNS + null, // HYDRATE_TRIGGER_CLEANUP_FNS ]; setLDeferBlockDetails(lView, adjustedIndex, lDetails); @@ -757,6 +762,13 @@ function applyDeferBlockState( ); markViewDirty(embeddedLView, NotificationSource.DeferBlockStateUpdate); } + + if (newState === DeferBlockState.Complete && Array.isArray(lDetails[ON_COMPLETE_FNS])) { + for (const callback of lDetails[ON_COMPLETE_FNS]) { + callback(); + } + lDetails[ON_COMPLETE_FNS] = null; + } } /** @@ -1082,3 +1094,19 @@ function triggerDeferBlock(lView: LView, tNode: TNode) { } } } + +export function triggerAndWaitForCompletion(deferBlock: any): Promise { + const lDetails = getLDeferBlockDetails(deferBlock.lView, deferBlock.tNode); + const promise = new Promise((resolve) => { + onDeferBlockCompletion(lDetails, resolve); + }); + triggerDeferBlock(deferBlock.lView, deferBlock.tNode); + return promise; +} + +function onDeferBlockCompletion(lDetails: LDeferBlockDetails, callback: VoidFunction) { + if (!Array.isArray(lDetails[ON_COMPLETE_FNS])) { + lDetails[ON_COMPLETE_FNS] = []; + } + lDetails[ON_COMPLETE_FNS].push(callback); +} diff --git a/packages/core/src/defer/interfaces.ts b/packages/core/src/defer/interfaces.ts index 8ee126b004d..72f33447437 100644 --- a/packages/core/src/defer/interfaces.ts +++ b/packages/core/src/defer/interfaces.ts @@ -158,6 +158,10 @@ export const STATE_IS_FROZEN_UNTIL = 2; export const LOADING_AFTER_CLEANUP_FN = 3; export const TRIGGER_CLEANUP_FNS = 4; export const PREFETCH_TRIGGER_CLEANUP_FNS = 5; +export const UNIQUE_SSR_ID = 6; +export const SSR_STATE = 7; +export const ON_COMPLETE_FNS = 8; +export const HYDRATE_TRIGGER_CLEANUP_FNS = 9; /** * Describes instance-specific defer block data. @@ -199,6 +203,26 @@ export interface LDeferBlockDetails extends Array { * List of cleanup functions for prefetch triggers. */ [PREFETCH_TRIGGER_CLEANUP_FNS]: VoidFunction[] | null; + + /** + * Unique id of this defer block assigned during SSR. + */ + [UNIQUE_SSR_ID]: string | null; + + /** + * Defer block state after SSR. + */ + [SSR_STATE]: number | null; + + /** + * A set of callbacks to be invoked once the main content is rendered. + */ + [ON_COMPLETE_FNS]: VoidFunction[] | null; + + /** + * List of cleanup functions for hydrate triggers. + */ + [HYDRATE_TRIGGER_CLEANUP_FNS]: VoidFunction[] | null; } /** diff --git a/packages/core/test/bundling/defer/bundle.golden_symbols.json b/packages/core/test/bundling/defer/bundle.golden_symbols.json index 18c5e2acc9e..f789b9099ee 100644 --- a/packages/core/test/bundling/defer/bundle.golden_symbols.json +++ b/packages/core/test/bundling/defer/bundle.golden_symbols.json @@ -377,6 +377,9 @@ { "name": "NullInjector" }, + { + "name": "ON_COMPLETE_FNS" + }, { "name": "ObjectUnsubscribedError" },