Skip to the solution
HardFrontend10 min read

Deferrable views — prefetch strategies and dependency isolation with @defer?

500 views

The problem

Question presented to candidate: "We wrapped our charting component in @defer, but the bundle analyser still shows the chart library in main.js. Explain how Angular decides what goes into a deferred chunk, and how prefetching changes when that chunk is downloaded."

What a strong answer should cover:

  • The compiler generates a dependency function per @defer block that returns dynamic import()s, and removes the matching static imports.
  • Dependency isolation rules: standalone dependencies only; not referenced eagerly elsewhere in the same file (outside the block, queries, class fields). Breaking the rule silently keeps them eager.
  • Transitive dependencies: whatever the deferred component imports goes with it.
  • Prefetch triggers (prefetch on idle | viewport | interaction | hover | immediate | timer(...), prefetch when) download code before the render trigger fires.
  • How to verify: lazy chunk in ng build output, or the compiled _DepsFn.

Clarifying questions expected:

  • "Is the chart component referenced anywhere else, for example by a query or a type used at runtime?"
  • "Do we know when users usually need the chart, to choose a prefetch trigger?"

Code / implementation expected: Yes — a @defer block with separate on and prefetch triggers, and a look at the compiled output.

  • deferrable-views
  • performance
  • angular-17

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read · 9 sections

Read the code

AngularDependency isolation: two deferred components split out, one shared component kept eager
import { Component } from "@angular/core";
import { ChartCmp } from "./chart";
import { ReviewsCmp } from "./reviews";
import { BadgeCmp } from "./shared";

@Component({
  selector: "app-root",
  imports: [ChartCmp, ReviewsCmp, BadgeCmp],
  template: `
    <app-badge />
    @defer (on viewport; prefetch on idle) {
      <app-chart />
      <app-badge />
    } @placeholder (minimum 500ms) {
      <p>chart placeholder</p>
    } @loading (after 100ms; minimum 1s) {
      <p>loading chart</p>
    } @error {
      <p>chart failed</p>
    }
    @defer (on interaction; hydrate on hover) {
      <app-reviews />
    } @placeholder {
      <button>Show reviews</button>
    }
  `,
})
export class AppComponent {}
AngularPrefetch separated from render: download on a timer, render on click
import { Component } from "@angular/core";
import { ChartCmp } from "./chart.js";

@Component({
  selector: "app-root",
  imports: [ChartCmp],
  template: `
    @defer (on interaction; prefetch on timer(100ms)) {
      <app-chart />
    } @placeholder {
      <button>Show chart</button>
    }
  `,
})
export class AppComponent {}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 100 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextHard

What is the difference between switchMap, mergeMap, concatMap, and exhaustMap?

Continue