mcpField
A
angular-zoneless

angular-zoneless

github.com/oguzhan18Development7169 installsUpdated 31w ago
Repository

About angular-zoneless

A practical guide for Angular developers adopting zoneless change detection in Angular 19+. It covers related APIs for signals, render callbacks, async handling, and testing.

Key features

  1. 01Enable zoneless change detection
  2. 02Use signal() and computed()
  3. 03Run post-render logic with afterNextRender
  4. 04Handle async data and manual detection
  5. 05Test in zoneless mode

Use cases

  1. 01Move an Angular app to zoneless mode
  2. 02Initialize DOM work after rendering
  3. 03Write tests for a zoneless app

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/oguzhan18/angular-ecosystem-skills --skill angular-zoneless

After installing, type/angular-zonelessin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/discussions/
_INDEX.md
references/docs/
_INDEX.md
references/issues/
_INDEX.md
references/releases/
_INDEX.md

Details

From the project README

Angular Zoneless

Version: Angular 19+ (2025) Tags: Zoneless, Change Detection, Signals, Reactivity

References: Zoneless Guide • Signals

API Changes

This section documents recent version-specific API changes.

  • NEW: provideZonelessChangeDetection — Enable zoneless mode source

  • NEW: afterNextRender — Run code after rendering without zone.js

  • NEW: Experimental Zoneless — Available since Angular 17, stable in Angular 19+

  • NEW: signal() + computed() — Works without zone.js

Best Practices

  • Enable zoneless change detection
export const appConfig: ApplicationConfig = {
  providers: [
    provideZonelessChangeDetection()
  ]
};
  • Use signals for reactivity
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <p>Count: {{ count() }}</p>
    <p>Double: {{ double() }}</p>
  `
})
export class CounterComponent {
  count = signal(0);
  double = computed(() => this.count() * 2);

  increment() {
    this.count.update(c => c + 1);
  }
}
  • Use afterNextRender for DOM operations
constructor() {
  afterNextRender(() => {
    // Runs after rendering, outside zone
    this.initChart();
  });
}
  • Use afterRender for repeated operations
constructor() {
  afterRender(() => {
    // Runs after every render
  });
}
  • Handle async without zone.js
@Component({
  template: `
    @if (data$ | async; as data) {
      {{ data.name }}
    }
  `
})
export class AsyncComponent {
  data$ = from(fetch('/api/data')).pipe(
    share()
  );
}
  • Use ChangeDetectorRef manually when needed
constructor(private cdr: ChangeDetectorRef) {}

update() {
  this.value = newValue;
  this.cdr.markForCheck();
}
  • Remove zone.js from polyfills
// polyfills.ts
// Remove or comment out zone.js import
// import 'zone.js';
  • Use untracked for non-reactive reads
import { untracked } from '@angular/core';

ngOnInit() {
  // Read without creating dependency
  const value = untracked(() => this.signal());
}
  • Handle browser events
@HostListener('click')
onClick() {
  // Works without zone.js
  this.count.update(c => c + 1);
}
  • Test in zoneless mode
TestBed.configureTestingModule({
  providers: [
    provideZonelessChangeDetection()
  ]
});

Comments

Markdown supported