This document describes Angular's defer block system, which enables declarative lazy loading of component dependencies directly in templates using the @defer syntax. Defer blocks allow portions of a template to be loaded on-demand based on triggers, reducing initial bundle size and improving application performance.
The implementation is centered around the ɵɵdefer instruction, which initializes the runtime data structures and manages the lifecycle of deferred content from initial placeholder to the final loaded state.
Defer blocks are Angular's template-level lazy loading mechanism. The system manages multiple states (placeholder, loading, error, complete) and supports various triggers (viewport, interaction, idle, timer, etc.).
Defer Block Template Syntax:
Sources: packages/core/src/defer/instructions.ts125-136 packages/core/test/bundling/defer/bundle.golden_symbols.json1-751
The defer block system implements a state machine with four primary states defined in DeferBlockState. Each state corresponds to a different template block and is rendered based on the loading lifecycle.
The state machine is managed through internal types and LView/TView slots:
| Entity | Role |
|---|---|
DeferBlockState | Public enum for states (Placeholder, Loading, Complete, Error) packages/core/src/defer/interfaces.ts36 |
DeferBlockInternalState | Internal tracking for hydration and transition logic packages/core/src/defer/interfaces.ts35 |
LDeferBlockDetails | Instance-specific state stored in LView packages/core/src/defer/interfaces.ts40 |
TDeferBlockDetails | Static metadata (template indices, resolver fn) stored in TView packages/core/src/defer/interfaces.ts41 |
Key state management functions:
ɵɵdefer(): Initializes the TDeferBlockDetails and LDeferBlockDetails packages/core/src/defer/instructions.ts125-220triggerDeferBlock(): Initiates the transition to the next state packages/core/src/defer/triggering.ts68renderPlaceholder(): Specifically handles the initial rendering of the placeholder block packages/core/src/defer/rendering.ts60Sources: packages/core/src/defer/instructions.ts156-173 packages/core/src/defer/interfaces.ts34-45 packages/core/test/bundling/defer/bundle.golden_symbols.json100-111
Defer blocks support multiple trigger types that determine when dependencies should be loaded or hydrated.
Angular distinguishes between "Regular Triggers" (for loading code) and "Hydrate Triggers" (for re-activating SSR content).
| Trigger Type | Implementation | Source |
|---|---|---|
| Idle | Uses requestIdleCallback via onIdleWrapper | packages/core/src/defer/instructions.ts32 |
| Viewport | Uses IntersectionObserver via onViewportWrapper | packages/core/src/defer/instructions.ts30 |
| Interaction | Event-based (click, etc.) via onInteraction | packages/core/src/defer/instructions.ts31 |
| Hover | Event-based (mouseenter) via onHover | packages/core/src/defer/instructions.ts31 |
| Timer | Scheduled via onTimer and TimerScheduler | packages/core/src/defer/instructions.ts46 |
Functions managing the trigger lifecycle:
shouldAttachTrigger(): Determines if a trigger should be bound based on current state packages/core/src/defer/triggering.ts71storeTriggerCleanupFn(): Persists a cleanup callback in the LDeferBlockDetails packages/core/src/defer/cleanup.ts29triggerResourceLoading(): The terminal action of most triggers, initiating the fetch of JS chunks packages/core/src/defer/triggering.ts70Sources: packages/core/src/defer/instructions.ts29-53 packages/core/src/defer/triggering.ts62-73 packages/core/src/defer/cleanup.ts29
When a defer block is triggered, the DependencyResolverFn (generated by the compiler) is executed.
triggerResourceLoading().dependencyResolverFn packages/core/src/defer/interfaces.ts38 is invoked.import() statements packages/core/test/acceptance/defer_spec.ts199loadingState moves from NOT_STARTED to IN_PROGRESS and finally COMPLETE or FAILED packages/core/src/defer/interfaces.ts37The compiler generates a specific function for each defer block:
AppComponent_Defer_6_DepsFn packages/core/test/bundling/defer/bundle.golden_symbols.json10
Sources: packages/core/src/defer/instructions.ts109-112 packages/core/src/defer/interfaces.ts37-38 packages/core/test/acceptance/defer_spec.ts196-203
Defer blocks are the primary boundary for Incremental Hydration. In SSR scenarios, defer blocks allow the server to render content that remains "frozen" (dehydrated) on the client until a hydration trigger is met.
DEHYDRATED_BLOCK_REGISTRY: A token for the DehydratedBlockRegistry which tracks blocks waiting for hydration packages/core/src/defer/instructions.ts54populateDehydratedViewsInLContainer(): Scans the DOM for ngh annotations to link server-rendered nodes to the LContainer packages/core/src/defer/instructions.ts15triggerHydrationFromBlockName(): Manually or automatically triggers the hydration of a specific block identified by its SSR ID (e.g., d0) packages/core/src/defer/instructions.ts49Sources: packages/core/src/defer/instructions.ts143-154 packages/core/src/hydration/annotate.ts154-155 packages/platform-server/test/incremental_hydration_spec.ts171-184
The defer system relies on a clear separation of symbols to ensure that code in a @defer block does not end up in the main bundle.
| Concept | Code Entity | Purpose |
|---|---|---|
| Instruction | ɵɵdefer | Entry point for runtime block creation packages/core/src/defer/instructions.ts125 |
| State Tracking | DEFER_BLOCK_STATE | Key in LDeferBlockDetails for current state packages/core/src/defer/interfaces.ts34 |
| Hydration ID | DEFER_BLOCK_SSR_ID_ATTRIBUTE | DOM attribute ngb used to identify blocks packages/core/src/hydration/event_replay.ts39 |
| Trigger Logic | onViewportWrapper | Implementation of on viewport trigger packages/core/src/defer/instructions.ts30 |
| Scheduler | TimerScheduler | Handles after and minimum timings packages/core/src/defer/timer_scheduler.ts44 |
The bundling tests verify that AppComponent_Defer_2_Template and AppComponent_Defer_6_DepsFn are part of the main chunk, but the actual component classes inside the @defer block are moved to a lazy chunk packages/core/test/bundling/defer/bundle.golden_symbols.json1-110
Sources: packages/core/test/bundling/defer/bundle.golden_symbols.json1-110 packages/core/src/defer/instructions.ts1-74
Refresh this wiki