Skip to content

Commit e33e673

Browse files
AndrewKushnirkirjs
authored andcommitted
refactor(core): do not serialize parent block id for top level blocks (#59190)
This commit updates incremental hydration-related annotation logic to avoid serializing parent block id when it's `null` (for top-level blocks). PR Close #59190
1 parent 69cd6f0 commit e33e673

File tree

4 files changed

+41
-8
lines changed

4 files changed

+41
-8
lines changed

packages/core/src/hydration/annotate.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,6 @@ function serializeLContainer(
405405

406406
// Add defer block into info context.deferBlocks
407407
const deferBlockInfo: SerializedDeferBlock = {
408-
[DEFER_PARENT_BLOCK_ID]: parentDeferBlockId,
409408
[NUM_ROOT_NODES]: rootNodes.length,
410409
[DEFER_BLOCK_STATE]: lDetails[CURRENT_DEFER_BLOCK_STATE],
411410
};
@@ -415,6 +414,11 @@ function serializeLContainer(
415414
deferBlockInfo[DEFER_HYDRATE_TRIGGERS] = serializedTriggers;
416415
}
417416

417+
if (parentDeferBlockId !== null) {
418+
// Serialize parent id only when it's present.
419+
deferBlockInfo[DEFER_PARENT_BLOCK_ID] = parentDeferBlockId;
420+
}
421+
418422
context.deferBlocks.set(deferBlockId, deferBlockInfo);
419423

420424
const node = unwrapRNode(lContainer);

packages/core/src/hydration/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export interface SerializedDeferBlock {
162162
/**
163163
* This contains the unique id of this defer block's parent, if it exists.
164164
*/
165-
[DEFER_PARENT_BLOCK_ID]: string | null;
165+
[DEFER_PARENT_BLOCK_ID]?: string;
166166

167167
/**
168168
* This field represents a status, based on the `DeferBlockState` enum.

packages/core/src/hydration/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ export function getParentBlockHydrationQueue(
571571
const deferBlockParents = transferState.get(NGH_DEFER_BLOCKS_KEY, {});
572572

573573
let isTopMostDeferBlock = false;
574-
let currentBlockId: string | null = deferBlockId;
574+
let currentBlockId: string | undefined = deferBlockId;
575575
let parentBlockPromise: Promise<void> | null = null;
576576
const hydrationQueue: string[] = [];
577577

packages/platform-server/test/incremental_hydration_spec.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ describe('platform-server partial hydration integration', () => {
222222
const ssrContents = getAppContents(html);
223223

224224
expect(ssrContents).toContain(
225-
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":2,"s":2}}',
225+
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":2,"s":2,"p":"d0"}}',
226226
);
227227
});
228228

@@ -285,9 +285,38 @@ describe('platform-server partial hydration integration', () => {
285285
const ssrContents = getAppContents(html);
286286

287287
expect(ssrContents).toContain(
288-
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":2,"s":2,"t":[2]}}',
288+
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":2,"s":2,"t":[2],"p":"d0"}}',
289289
);
290290
});
291+
292+
it('should not include parent id in serialized data for top-level `@defer` blocks', async () => {
293+
@Component({
294+
selector: 'app',
295+
template: `
296+
@defer (on viewport; hydrate on interaction) {
297+
Hello world!
298+
} @placeholder {
299+
<span>Placeholder</span>
300+
}
301+
`,
302+
})
303+
class SimpleComponent {}
304+
305+
const appId = 'custom-app-id';
306+
const providers = [{provide: APP_ID, useValue: appId}];
307+
const hydrationFeatures = () => [withIncrementalHydration()];
308+
309+
const html = await ssr(SimpleComponent, {
310+
envProviders: providers,
311+
hydrationFeatures,
312+
});
313+
314+
const ssrContents = getAppContents(html);
315+
316+
// Assert that the serialized data doesn't contain the "p" field,
317+
// which contains parent id (which is not needed for top-level blocks).
318+
expect(ssrContents).toContain('"__nghDeferData__":{"d0":{"r":1,"s":2}}}');
319+
});
291320
});
292321

293322
describe('basic hydration behavior', () => {
@@ -347,7 +376,7 @@ describe('platform-server partial hydration integration', () => {
347376
expect(ssrContents).toContain('<p jsaction="click:;keydown:;" ngb="d1');
348377
// There is an extra annotation in the TransferState data.
349378
expect(ssrContents).toContain(
350-
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":1,"s":2}}',
379+
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":1,"s":2,"p":"d0"}}',
351380
);
352381
// Outer defer block is rendered.
353382
expect(ssrContents).toContain('Main defer block rendered');
@@ -460,7 +489,7 @@ describe('platform-server partial hydration integration', () => {
460489
expect(ssrContents).toContain('<p jsaction="click:;keydown:;" ngb="d1');
461490
// There is an extra annotation in the TransferState data.
462491
expect(ssrContents).toContain(
463-
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":1,"s":2}}',
492+
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":1,"s":2,"p":"d0"}}',
464493
);
465494
// Outer defer block is rendered.
466495
expect(ssrContents).toContain('Main defer block rendered');
@@ -569,7 +598,7 @@ describe('platform-server partial hydration integration', () => {
569598
// <p> is inside a nested defer block -> different namespace.
570599
// expect(ssrContents).toContain('<p jsaction="click:;" ngb="d1');
571600
// There is an extra annotation in the TransferState data.
572-
expect(ssrContents).toContain('"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2}}');
601+
expect(ssrContents).toContain('"__nghDeferData__":{"d0":{"r":1,"s":2}}');
573602
// Outer defer block is rendered.
574603
expect(ssrContents).toContain('Main defer block rendered');
575604
// Inner defer block should only display placeholder.

0 commit comments

Comments
 (0)