Skip to content

Commit

Permalink
fix(core): avoid triggering on timer and on idle on the server
Browse files Browse the repository at this point in the history
This commit updates defer block logic to avoid triggering `on idle` and `on timer` on the server for regular SSR mode (when incremental hydration is not enabled). Triggering the mentioned condition resulted in invoking `setTimeout` calls, which delayed serialization on the server during SSR (the process was waiting for the timeouts to clear).
  • Loading branch information
AndrewKushnir committed Dec 13, 2024
1 parent f3729ce commit 5182ab6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
10 changes: 8 additions & 2 deletions packages/core/src/defer/triggering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,17 @@ export function scheduleDelayedTrigger(
) {
const lView = getLView();
const tNode = getCurrentTNode()!;
const injector = lView[INJECTOR];
const lDetails = getLDeferBlockDetails(lView, tNode);

renderPlaceholder(lView, tNode);

// Exit early to avoid invoking `scheduleFn`, which would
// add `setTimeout` call and potentially delay serialization
// on the server unnecessarily.
if (!shouldTriggerDeferBlock(TriggerType.Regular, lView)) return;

const injector = lView[INJECTOR];
const lDetails = getLDeferBlockDetails(lView, tNode);

const cleanupFn = scheduleFn(
() => triggerDeferBlock(TriggerType.Regular, lView, tNode),
injector,
Expand Down
35 changes: 35 additions & 0 deletions packages/platform-server/test/full_app_hydration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3052,6 +3052,41 @@ describe('platform-server full application hydration integration', () => {
expect(clientRootNode.outerHTML).toContain('<my-lazy-cmp>Hi!</my-lazy-cmp>');
});

it('should not trigger `setTimeout` calls for `on timer` triggers on the server', async () => {
const setTimeoutSpy = spyOn(globalThis, 'setTimeout').and.callThrough();

@Component({
selector: 'my-lazy-cmp',
standalone: true,
template: 'Hi!',
})
class MyLazyCmp {}

@Component({
standalone: true,
selector: 'app',
imports: [MyLazyCmp],
template: `
@defer (on timer(123ms)) {
<my-lazy-cmp />
}
`,
})
class SimpleComponent {}

const html = await ssr(SimpleComponent);

const ssrContents = getAppContents(html);
expect(ssrContents).toContain('<app ngh');

// Make sure that there were no `setTimeout` calls with the # of ms
// defined in the `on timer` trigger.
for (let i = 0; i < setTimeoutSpy.calls.count(); i++) {
const args = setTimeoutSpy.calls.argsFor(i);
expect(args[1]).not.toBe(123, 'on timer was triggered during SSR unexpectedly');
}
});

it('should hydrate a placeholder block', async () => {
@Component({
selector: 'my-lazy-cmp',
Expand Down

0 comments on commit 5182ab6

Please sign in to comment.