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.