Vues Différables (@defer)
Lazy load components using Angular’s built-in @defer block.
Basic @defer
Section intitulée « Basic @defer »@Component({ template: ` @defer { <app-comments [albumId]="albumId"></app-comments> } @placeholder { <p>Click to load comments</p> } `})export class DetailComponent { albumId = input.required<number>();}@defer Triggers
Section intitulée « @defer Triggers »on interaction
Section intitulée « on interaction »Load when user interacts with the trigger element:
@defer (on interaction) { <app-comments [albumId]="albumId"></app-comments>} @placeholder { <a>Load comments</a>}on viewport
Section intitulée « on viewport »Load when element enters viewport:
@defer (on viewport) { <app-heavy-chart [data]="chartData"></app-heavy-chart>} @placeholder { <div style="height: 400px">Chart will load when visible</div>}Load when browser is idle:
@defer (on idle) { <app-analytics-widget></app-analytics-widget>} @placeholder { <div>Loading analytics...</div>}on immediate
Section intitulée « on immediate »Load immediately (useful for testing):
@defer (on immediate) { <app-widget></app-widget>}on timer
Section intitulée « on timer »Load after specified milliseconds:
@defer (on timer(5000)) { <app-ads></app-ads>} @placeholder { <div>Ad loads in 5 seconds</div>}on hover
Section intitulée « on hover »Load when user hovers over trigger:
@defer (on hover) { <app-tooltip [content]="tooltipText"></app-tooltip>} @placeholder { <span>Hover for more info</span>}@loading Block
Section intitulée « @loading Block »Show content while lazy chunk loads:
@defer (on interaction) { <app-comments></app-comments>} @loading { <p>Loading comments...</p>} @placeholder { <a>Load comments</a>}minimum and after
Section intitulée « minimum and after »Control when loading state shows:
@defer (on interaction) { <app-comments></app-comments>} @loading (after 100ms; minimum 1s) { <p>Loading...</p>} @placeholder { <a>Load comments</a>}after- Delay before showing loading stateminimum- Minimum time à show loading state (prevents flash)
@error Block
Section intitulée « @error Block »Handle loading failures:
@defer (on viewport) { <app-comments></app-comments>} @error { <p>Failed to load comments. Please try again.</p>} @placeholder { <div>Comments section</div>}@placeholder Block
Section intitulée « @placeholder Block »Content shown before deferral triggers:
@defer (on viewport) { <app-heavy-component></app-heavy-component>} @placeholder (minimum 500ms) { <div class="skeleton">Loading...</div>}Multiple Triggers
Section intitulée « Multiple Triggers »Combine multiple trigger conditions:
@defer (on interaction; on timer(5000)) { <app-widget></app-widget>} @placeholder { <div>Widget loads on click or after 5s</div>}Prefetching
Section intitulée « Prefetching »Prefetch lazy chunk before showing:
@defer (on interaction; prefetch on idle) { <app-comments></app-comments>} @placeholder { <a>Load comments</a>}Named Triggers
Section intitulée « Named Triggers »Utiliser specific éléments as triggers:
<button #loadBtn>Load Comments</button>
@defer (on interaction(loadBtn)) { <app-comments></app-comments>} @placeholder { <p>Click button above to load</p>}Complete Exemple
Section intitulée « Complete Exemple »@Component({ template: ` <div class="album-detail"> <h1>{{ album.name }}</h1> <p>{{ album.description }}</p>
@defer (on interaction; prefetch on idle) { <app-comments [albumId]="album.id"></app-comments> } @loading (after 200ms; minimum 1s) { <div class="loading-spinner"> <p>Loading comments...</p> </div> } @placeholder { <a class="load-link">Load comments</a> } @error { <p class="error">Failed to load comments.</p> } </div> `})export class AlbumDetailComponent { album = input.required<Album>();}Nested @defer
Section intitulée « Nested @defer »@defer (on viewport) { <app-section> @defer (on interaction) { <app-nested-component></app-nested-component> } @placeholder { <button>Load more</button> } </app-section>} @placeholder { <div>Section placeholder</div>}Tests Vues Différables
Section intitulée « Tests Vues Différables »import { ComponentFixture, TestBed } from '@angular/core/testing';import { Component } from '@angular/core';
describe('DeferrableViews', () => { it('should render placeholder initially', () => { @Component({ template: ` @defer { <app-comments></app-comments> } @placeholder { <p>Placeholder</p> } ` }) class TestComponent {}
const fixture = TestBed.createComponent(TestComponent); fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('Placeholder'); });});When to Use @defer
Section intitulée « When to Use @defer »✅ Good use cases:
- Heavy components (charts, ediaurs)
- Below-the-fold content
- Components with large dependencies
- Modal/dialog content
- Comments sections
- Admin features
❌ Avoid for:
- Critical above-the-fold content
- Small components
- Components needed immediately
- Navigation éléments
Performance Benefits
Section intitulée « Performance Benefits »// ❌ Bad: Eagerly loads heavy component@Component({ template: ` @if (showComments()) { <app-comments></app-comments> } `})
// ✅ Good: Lazy loads on demand@Component({ template: ` @defer (on interaction) { <app-comments></app-comments> } @placeholder { <a>Load comments</a> } `})Bonnes Pratiques
Section intitulée « Bonnes Pratiques »- Utiliser
@loadingwithafterà avoid loading flashes - Utiliser
minimumà prevent loading flash on fast connections - Prefetch on
idlepour une meilleure UX - Utiliser
@errorfor robust error handling - Combine triggers for flexibility
- Utiliser
@placeholder (minimum)à prevent layout shifts - Defer heavy third-party components
- Test deferrable views in slow network conditions
Bundle Size Impact
Section intitulée « Bundle Size Impact »# Before @defermain.js: 500kb (includes CommentsComponent)
# After @defermain.js: 350kblazy-comments.js: 150kb (loaded on demand)
