S

super-dev — full-stack

@super-dev.app · Full-stack · ★ ouvert aux missions
12,8k abonnés·47 vidéos·Actif depuis 2017

Développeur full-stack .NET / Angular avec une casquette DevOps sur Azure Cloud. Aussi à l'aise sur Flutter + Firebase. Je construis des produits, je les déploie, je les surveille.

Retour aux articles
ANGULAR
ANGULAR

@defer et le nouveau control flow : moins de JS au démarrage

Article 3 sur 4 — Angular 21 en pratique
Zoneless, signals, resource(), @defer, SignalStore — le front moderne, en vrai.

Le nouveau control flow d'Angular ne se contente pas de remplacer *ngIf et *ngFor par une syntaxe plus jolie. Couplé à @defer , il change ce qui finit dans le bundle initial : on n'expédie au démarrage que le JavaScript réellement nécessaire au premier rendu, le reste arrive à la demande.

@if, @for, @switch

La syntaxe @ est intégrée au compilateur : pas d'import de directive, et un track obligatoire sur @for qui force à réfléchir à l'identité des éléments. C'est ce track qui évite de tout re-créer dans le DOM à chaque changement de liste.

TypeScript
1@if (user(); as currentUser) {
2 <p>Bonjour {{ currentUser.name }}</p>
3} @else {
4 <p>Invité</p>
5}
6
7@for (item of items(); track item.id) {
8 <li>{{ item.label }}</li>
9} @empty {
10 <li>Aucun élément</li>
11}
12
13@switch (status()) {
14 @case ('loading') { <spinner /> }
15 @case ('error') { <error-banner /> }
16 @default { <content /> }
17}

Le bloc @empty de @for et le @case exhaustif de @switch couvrent des cas qu'on oubliait souvent avec les directives structurelles.

@defer : charger plus tard

@defer enveloppe un bout de template dont le code est sorti du bundle principal et chargé en chunk séparé au moment voulu. Le déclencheur décide quand : on viewport charge quand le bloc entre dans l'écran, on interaction au premier clic/focus, on idle quand le navigateur est inactif, on hover , ou on timer .

TypeScript
1@defer (on viewport) {
2 <heavy-comments [postId]="postId()" />
3} @placeholder (minimum 200ms) {
4 <p>Commentaires</p>
5} @loading (after 100ms; minimum 300ms) {
6 <skeleton-list />
7} @error {
8 <p>Impossible de charger les commentaires.</p>
9}

Les blocs annexes

  • @placeholder : rendu avant tout déclenchement, c'est lui qui peut porter le trigger

on viewport / on interaction . Le minimum évite un flash trop bref.

  • @loading : pendant la récupération du chunk ; after retarde son affichage pour ne pas

clignoter sur une connexion rapide.

  • @error : si le chunk ne charge pas (réseau coupé, par exemple).

On peut aussi pré-charger sans afficher avec prefetch on hover , pour que le clic soit instantané sans alourdir le démarrage.

L'impact sur le bundle

Tout composant, directive ou pipe utilisé uniquement dans un bloc @defer est extrait dans son propre chunk. Une page lourde — éditeur de code, graphiques, carte — peut ainsi sortir 100 à 200 ko du bundle initial, qui ne se téléchargent que si l'utilisateur scrolle jusque-là. Le gain se mesure directement sur le Largest Contentful Paint et le temps d'interactivité. La doc détaille chaque déclencheur dans le guide du chargement différé .

Attention toutefois : un @defer (on viewport) placé au-dessus de la ligne de flottaison se déclenche immédiatement et n'apporte rien. Le différé n'a de sens que pour ce qui est hors écran ou conditionnel.

Le control flow rend l'intention lisible, @defer rend le coût explicite. Plutôt que de tout charger « au cas où », tu déclares quand chaque morceau mérite son JavaScript — et le démarrage s'allège tout seul.
super-dev — portfolio.app
// Continuer dans ANGULAR
Un moteur façon DOOM dans le navigateur, à trois backends
11 min • 1,4k lectures
Passer une app Angular en zoneless + signals
8 min • 4,1k lectures
Charger des données avec resource() et httpResource()
7 min • 3,6k lectures