Skip to the solution
HardFrontend9 min read

What is the critical render path and how does Angular handle font and style optimization?

277 views

The problem

Question presented to candidate: "Our Lighthouse report says 'Eliminate render-blocking resources' and points at our stylesheet and Google Fonts link. Explain the critical render path, and what the Angular build already does about styles and fonts."

What a strong answer should cover:

  • Critical render path: HTML parsing, CSSOM, render tree, layout, paint; CSS and web fonts block first paint, deferred scripts do not.
  • Angular production builds: critical CSS inlining (Beasties) of the rules the initial HTML uses, and async loading of the full stylesheet (media="print" swap plus <noscript>).
  • Critical CSS only helps when the HTML has content: SSR or prerendering, not an empty CSR shell.
  • Font inlining (optimization.fonts.inline) for Google Fonts and Adobe Fonts CSS at build time.
  • Scripts as type="module" with modulepreload; component styles bundled in JS (and emitted in the head during SSR).
  • Related levers: NgOptimizedImage priority preload, @defer, budgets in angular.json.

Clarifying questions expected:

  • "Is the app server-rendered or prerendered? That decides whether critical CSS inlining can do anything."
  • "Are fonts self-hosted or from Google Fonts?"

Code / implementation expected: Optional β€” the relevant angular.json options and a look at the built index.html.

  • performance
  • optimization

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

9 min read Β· 9 sections

Read the code

AngularThe component used for the build experiments: a priority hero image, SSR content and a deferred chart
import { Component, signal } from '@angular/core';
import { NgOptimizedImage } from '@angular/common';
import { Chart } from './parts/chart';
import { Clock } from './parts/clock';

@Component({
  selector: 'app-root',
  imports: [Chart, Clock, NgOptimizedImage],
  template: `
    <h1>Shop</h1>
    <img ngSrc="https://cdn.example.com/hero.jpg" width="800" height="400" priority alt="hero" />
    <ul>
      @for (p of products(); track p) { <li>{{ p }}</li> }
    </ul>
    <button (click)="count.set(count() + 1)">Clicked {{ count() }}</button>
    <app-clock ngSkipHydration />
    @defer (on viewport) {
      <app-chart />
    } @placeholder {
      <p>chart placeholder</p>
    }
  `,
})
export class App {
  protected readonly products = signal(['Tea', 'Coffee']);
  protected readonly count = signal(0);
}

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 114 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

How does Angular's dependency resolution search work using @Self(), @SkipSelf(), @Optional(), and @Host()?

Continue