Skip to main content

Lab 21: Deferrable Views (@defer)

πŸ“– Resources​

πŸš€ Starter Code​

step-18-album-wholesale-v21-post-signal-form

In this lab you will use Angular's @defer block to lazily load heavy components only when they are actually needed. You will explore the different trigger types and observe the network impact in the browser's DevTools.

πŸ“ Instructions​

Step 1: Identify a Heavy Component​

Find a component in the app that is rendered below the fold and is relatively expensive to render (e.g., AlbumDetailComponent, chart, or CartSummaryComponent).

Step 2: Wrap the Component with @defer​

Replace the direct template reference with a @defer block:

<!-- Before -->
<app-album-detail [album]="selected" />

<!-- After -->
@defer {
<app-album-detail [album]="selected" />
} @loading {
<p>Loading details…</p>
} @placeholder {
<div class="placeholder-box">Hover to preview</div>
} @error {
<p>Could not load component.</p>
}

Step 3: Experiment with Triggers​

Test each trigger by modifying the @defer line:

<!-- Load when the browser is idle -->
@defer (on idle) { ... }

<!-- Load when the block enters the viewport -->
@defer (on viewport) { ... }

<!-- Load when the user clicks a button -->
<button #loadBtn>Load details</button>
@defer (on interaction(loadBtn)) { ... }

<!-- Load when the user hovers -->
@defer (on hover(loadBtn)) { ... }

<!-- Load after a fixed delay -->
@defer (on timer(3s)) { ... }

<!-- Load immediately (but in a deferred chunk) -->
@defer (on immediate) { ... }

Open the browser's Network tab, filter by JS, and verify that the component's chunk only downloads when triggered.

Step 4: Add Prefetching​

Prefetch the chunk early while still delaying rendering:

@defer (on interaction(loadBtn); prefetch on idle) {
<app-album-detail [album]="selected" />
} @placeholder {
<button #loadBtn>Show details</button>
}

Observe in the Network tab: the JS chunk is downloaded during idle time, so there is no delay on click.

Step 5: Set Timing Options​

Add minimum display time for @loading to avoid flickers:

@defer (on viewport; prefetch on idle) {
<app-album-detail [album]="selected" />
} @loading (after 200ms; minimum 500ms) {
<p>Loading…</p>
} @placeholder (minimum 300ms) {
<div class="placeholder-box"></div>
}

Step 6: Verify the Bundle Split​

Run the production build and confirm the component is in a separate chunk:

ng build

Inspect the output in dist/ β€” the deferred component should appear as a separate JS file.