S

super-dev — full-stack

@super-dev.app · Full-stack · ★ open to work
12.8k subscribers·47 videos·Active since 2017

Full-stack .NET / Angular dev with a DevOps streak on Azure Cloud. Also fluent in Flutter + Firebase. I build products, ship them, and keep them healthy.

Back to articles
ANGULAR
ANGULAR

@defer and the new control flow: less JS at startup

Article 3 of 4 — Angular 21 in practice
Zoneless, signals, resource(), @defer, SignalStore — the modern front end, for real.

Angular's new control flow doesn't just swap *ngIf and *ngFor for nicer syntax. Paired with @defer , it changes what ends up in the initial bundle: at startup you ship only the JavaScript actually needed for the first render, and the rest arrives on demand.

@if, @for, @switch

The @ syntax is built into the compiler: no directive import, and a mandatory track on @for that forces you to think about element identity. That track is what avoids re-creating the whole DOM on every list change.

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

The @empty block on @for and the exhaustive @case on @switch cover cases that were often forgotten with structural directives.

@defer: load later

@defer wraps a slice of template whose code is pulled out of the main bundle and loaded as a separate chunk at the right moment. The trigger decides when: on viewport loads when the block enters the screen, on interaction on the first click/focus, on idle when the browser is idle, on hover , or on timer .

TypeScript
1@defer (on viewport) {
2 <heavy-comments [postId]="postId()" />
3} @placeholder (minimum 200ms) {
4 <p>Comments</p>
5} @loading (after 100ms; minimum 300ms) {
6 <skeleton-list />
7} @error {
8 <p>Couldn't load comments.</p>
9}

The companion blocks

  • @placeholder : rendered before any trigger fires — it's the one that can carry the

on viewport / on interaction trigger. The minimum avoids a too-brief flash.

  • @loading : while the chunk is fetched; after delays its display so it doesn't flicker on

a fast connection.

  • @error : if the chunk fails to load (dropped network, for instance).

You can also prefetch without rendering using prefetch on hover , so the click is instant without weighing down startup.

The bundle impact

Any component, directive or pipe used only inside a @defer block is extracted into its own chunk. A heavy page — code editor, charts, map — can thus pull 100 to 200 kB out of the initial bundle, downloaded only if the user scrolls that far. The win shows up directly in Largest Contentful Paint and time to interactive. The docs detail every trigger in the deferred loading guide .

One caveat though: a @defer (on viewport) placed above the fold fires immediately and buys you nothing. Deferring only makes sense for what is off-screen or conditional.

Control flow makes intent readable, @defer makes cost explicit. Rather than loading everything "just in case", you declare when each piece earns its JavaScript — and startup gets lighter on its own.
super-dev — portfolio.app
// More in ANGULAR
A DOOM-style engine in the browser, with three backends
11 min • 1.4k reads
Take an Angular app zoneless + signals
8 min • 4.1k reads
Loading data with resource() and httpResource()
7 min • 3.6k reads