mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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
This commit is contained in:
@@ -405,7 +405,6 @@ function serializeLContainer(
|
||||
|
||||
// Add defer block into info context.deferBlocks
|
||||
const deferBlockInfo: SerializedDeferBlock = {
|
||||
[DEFER_PARENT_BLOCK_ID]: parentDeferBlockId,
|
||||
[NUM_ROOT_NODES]: rootNodes.length,
|
||||
[DEFER_BLOCK_STATE]: lDetails[CURRENT_DEFER_BLOCK_STATE],
|
||||
};
|
||||
@@ -415,6 +414,11 @@ function serializeLContainer(
|
||||
deferBlockInfo[DEFER_HYDRATE_TRIGGERS] = serializedTriggers;
|
||||
}
|
||||
|
||||
if (parentDeferBlockId !== null) {
|
||||
// Serialize parent id only when it's present.
|
||||
deferBlockInfo[DEFER_PARENT_BLOCK_ID] = parentDeferBlockId;
|
||||
}
|
||||
|
||||
context.deferBlocks.set(deferBlockId, deferBlockInfo);
|
||||
|
||||
const node = unwrapRNode(lContainer);
|
||||
|
||||
@@ -158,7 +158,7 @@ export interface SerializedDeferBlock {
|
||||
/**
|
||||
* This contains the unique id of this defer block's parent, if it exists.
|
||||
*/
|
||||
[DEFER_PARENT_BLOCK_ID]: string | null;
|
||||
[DEFER_PARENT_BLOCK_ID]?: string;
|
||||
|
||||
/**
|
||||
* This field represents a status, based on the `DeferBlockState` enum.
|
||||
|
||||
@@ -571,7 +571,7 @@ export function getParentBlockHydrationQueue(
|
||||
const deferBlockParents = transferState.get(NGH_DEFER_BLOCKS_KEY, {});
|
||||
|
||||
let isTopMostDeferBlock = false;
|
||||
let currentBlockId: string | null = deferBlockId;
|
||||
let currentBlockId: string | undefined = deferBlockId;
|
||||
let parentBlockPromise: Promise<void> | null = null;
|
||||
const hydrationQueue: string[] = [];
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ describe('platform-server partial hydration integration', () => {
|
||||
const ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain(
|
||||
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":2,"s":2}}',
|
||||
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":2,"s":2,"p":"d0"}}',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -285,9 +285,38 @@ describe('platform-server partial hydration integration', () => {
|
||||
const ssrContents = getAppContents(html);
|
||||
|
||||
expect(ssrContents).toContain(
|
||||
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":2,"s":2,"t":[2]}}',
|
||||
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":2,"s":2,"t":[2],"p":"d0"}}',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not include parent id in serialized data for top-level `@defer` blocks', async () => {
|
||||
@Component({
|
||||
selector: 'app',
|
||||
template: `
|
||||
@defer (on viewport; hydrate on interaction) {
|
||||
Hello world!
|
||||
} @placeholder {
|
||||
<span>Placeholder</span>
|
||||
}
|
||||
`,
|
||||
})
|
||||
class SimpleComponent {}
|
||||
|
||||
const appId = 'custom-app-id';
|
||||
const providers = [{provide: APP_ID, useValue: appId}];
|
||||
const hydrationFeatures = () => [withIncrementalHydration()];
|
||||
|
||||
const html = await ssr(SimpleComponent, {
|
||||
envProviders: providers,
|
||||
hydrationFeatures,
|
||||
});
|
||||
|
||||
const ssrContents = getAppContents(html);
|
||||
|
||||
// Assert that the serialized data doesn't contain the "p" field,
|
||||
// which contains parent id (which is not needed for top-level blocks).
|
||||
expect(ssrContents).toContain('"__nghDeferData__":{"d0":{"r":1,"s":2}}}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('basic hydration behavior', () => {
|
||||
@@ -347,7 +376,7 @@ describe('platform-server partial hydration integration', () => {
|
||||
expect(ssrContents).toContain('<p jsaction="click:;keydown:;" ngb="d1');
|
||||
// There is an extra annotation in the TransferState data.
|
||||
expect(ssrContents).toContain(
|
||||
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":1,"s":2}}',
|
||||
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":1,"s":2,"p":"d0"}}',
|
||||
);
|
||||
// Outer defer block is rendered.
|
||||
expect(ssrContents).toContain('Main defer block rendered');
|
||||
@@ -460,7 +489,7 @@ describe('platform-server partial hydration integration', () => {
|
||||
expect(ssrContents).toContain('<p jsaction="click:;keydown:;" ngb="d1');
|
||||
// There is an extra annotation in the TransferState data.
|
||||
expect(ssrContents).toContain(
|
||||
'"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2},"d1":{"p":"d0","r":1,"s":2}}',
|
||||
'"__nghDeferData__":{"d0":{"r":1,"s":2},"d1":{"r":1,"s":2,"p":"d0"}}',
|
||||
);
|
||||
// Outer defer block is rendered.
|
||||
expect(ssrContents).toContain('Main defer block rendered');
|
||||
@@ -569,7 +598,7 @@ describe('platform-server partial hydration integration', () => {
|
||||
// <p> is inside a nested defer block -> different namespace.
|
||||
// expect(ssrContents).toContain('<p jsaction="click:;" ngb="d1');
|
||||
// There is an extra annotation in the TransferState data.
|
||||
expect(ssrContents).toContain('"__nghDeferData__":{"d0":{"p":null,"r":1,"s":2}}');
|
||||
expect(ssrContents).toContain('"__nghDeferData__":{"d0":{"r":1,"s":2}}');
|
||||
// Outer defer block is rendered.
|
||||
expect(ssrContents).toContain('Main defer block rendered');
|
||||
// Inner defer block should only display placeholder.
|
||||
|
||||
Reference in New Issue
Block a user