skip to content

With the Angular CLI dev server, which edits are hot-replaced without a page reload, which cause a full reload, and what can switch HMR off?

level: middleimportance: should knowfreq 40%

answer

  1. styles and templates, not TypeScript
  2. hmr defaults to liveReload
  3. needs AOT
  4. hashed bundles disable it
  5. TypeScript edits reload the page

basics

~10 s

ng serve hot-replaces global styles and component templates and styles; TypeScript changes reload the page. HMR is off with --no-hmr, without live reload, in JIT builds, or when outputHashing is all or bundles.

solid answer

~40 s

The dev server's HMR is not general JavaScript module replacement. It covers three things: global stylesheets from the `styles` option, component stylesheets, and component templates, both inline and file-based. For those, the build recompiles the minimum and the running app swaps in the new styles or template while keeping its state. Any other change, such as a component class, a service or routes, triggers a full page reload through live reload. `hmr` defaults to the value of `liveReload` (which is `true`), and `ng serve --no-hmr` disables it. Component HMR also requires AOT. The dev server turns HMR off with a warning when the served build has `outputHashing` set to `all` or `bundles`, which is the case for `ng serve --configuration production`.

code

bash · 3 lines
bash
ng serve                           # HMR on for styles and templates
ng serve --no-hmr                  # every change reloads the page
ng serve --configuration production  # HMR disabled: outputHashing is 'all'

go deeper

for a junior

Know that saving a template or stylesheet updates the page in place, while changing TypeScript reloads it.

for a middle

Explain the hmr and liveReload options, the AOT requirement, and why outputHashing all or bundles disables HMR.

for a senior

Diagnose missing HMR from the served configuration, encapsulation and file type, and tune prebundling and polling for large or containerised projects.

for a principal

Weigh developer-loop speed against configuration drift when teams serve non-default configurations, and set what the standard local workflow is.

## Two ways the browser gets your change When you save a file under `ng serve`, the `@angular/build:dev-server` builder rebuilds incrementally. It then tells the browser one of two things: - **Hot module replacement (HMR)**: patch the running page in place, so most application state survives, such as the current route and data held in services. - **Live reload**: reload the whole page, so the app boots again from scratch. The Angular docs are explicit that general JavaScript HMR is *not* supported. What is supported is a set of Angular-specific replacements. ## What is hot-replaced | Edit | Result | |---|---| | Global stylesheet (`styles` build option, for example `styles.scss`) | CSS swapped in place | | Component stylesheet (`styleUrl`/`styleUrls` or inline `styles`) | Component updated with the new styles, no page reload | | Component template (`templateUrl` or inline `template`) | Template swapped for live instances | | Component class, service, routes, `app.config.ts` or other TypeScript | Full page reload | For style-only changes, the build compiles the minimum amount of application code. For template changes, Angular's runtime swaps in the recompiled component definition and re-creates that component's views, while services, router state and the rest of the app are left alone. ## The switches 1. **`hmr`**: a dev-server option that defaults to the value of `liveReload`. `ng serve --no-hmr` turns it off, so every change becomes a full reload. 2. **`liveReload`**: defaults to `true`. Turning it off turns off component HMR as well, and since `hmr` defaults to `liveReload`, HMR in general unless you set `hmr` explicitly. 3. **AOT**: component HMR requires the build target's `aot` to be `true` (the default). A JIT build falls back to reloads. 4. **`outputHashing`**: if the build configuration being served uses `all` or `bundles`, the dev server disables HMR and logs a warning that the setting is incompatible. This bites people who run `ng serve --configuration production`. 5. **Environment variables** exist for troubleshooting, such as `NG_HMR_TEMPLATES=0` to stop template hot replacement while keeping style HMR. ## Related dev-server behaviour - **Prebundling.** On first start the dev server processes third-party dependencies once (`prebundle`, default `true`), so rebuilds do not re-bundle them. Excluding one package with `prebundle.exclude` is preferred over disabling it, which slows rebuilds. - **A flash of unstyled content** can appear on startup, because stylesheet processing is deferred until first use. It does not happen in real builds. - **Watching.** `watch` defaults to `true`. `poll` sets a polling interval for file systems where native file events are unreliable, such as some containers and network drives. ## Prebundling and file watching in practice The Angular docs list three situations where prebundling needs attention: - a dependency's imports need custom `loader` behaviour; - a dependency is symlinked to local code, for example with `npm link`, and edits to it must be picked up; - prebundling a dependency fails with an error. The fix is usually to exclude that one package: ```json "serve": { "builder": "@angular/build:dev-server", "options": { "prebundle": { "exclude": ["some-dep"] } } } ``` Prebundling also requires the Angular CLI cache to be enabled. On file systems that do not deliver change events, `ng serve --poll 1000` makes the watcher check every second, at the cost of CPU. ## Diagnosing "HMR doesn't work" - Check the terminal for the warning about `outputHashing`, and check which configuration you are serving. - Check what you edited: a change to a `.ts` file is supposed to reload the page. - Confirm `aot` has not been set to `false` in the development configuration. - If the state that disappears lives in a component class you edited, a reload was expected. ## Why interviewers ask HMR claims are easy to overstate. A candidate who says "Angular has full HMR" or "Angular has no HMR" is wrong both ways. The accurate model covers templates and styles hot, code reloads, and a few switches that turn it off. It also shows the candidate has used a current dev server rather than the old webpack one.

  • Why does the dev server disable HMR when `outputHashing` is `all`?
    HMR updates the running page by referring to the files it already loaded. When bundle names carry content hashes, every rebuild renames them, so those references break. The dev server therefore turns HMR off and logs a warning. The development configuration leaves `outputHashing` at `none`, which is why HMR works there.
  • You edit a service and the form you were testing loses its input. Is HMR broken?
    No. Only global styles, component styles and component templates are hot-replaced. A service is TypeScript code, so the dev server sends a full page reload and the application boots from scratch, losing in-memory state. Keep the state in the URL or storage if you need it across reloads while developing.

saying these in an interview costs you the question

  • Claims Angular's dev server hot-swaps any TypeScript module without reloading
  • Believes HMR must be enabled with a flag and extra code in main.ts
  • Expects HMR to work under ng serve --configuration production
  • Thinks editing a component template always forces a full page reload
  • Blames HMR when an edit to a service reloads the page, which is by design