Why Use Zoneless?
Removing ZoneJS from an Angular application offers several advantages:
- Improved performance: ZoneJS frequently triggers application synchronization, even when the state hasn't changed.
- Better Core Web Vitals: Eliminating ZoneJS reduces payload size and startup time.
- Easier debugging: ZoneJS makes stack traces harder to interpret.
- Enhanced ecosystem compatibility: Some browser APIs and third-party libraries are incompatible with ZoneJS, making maintenance more complex.
Enabling Zoneless in an Application
The API for zoneless mode is experimental and subject to change. To enable zoneless mode:
Standalone Bootstrap
bootstrapApplication(MyApp, {providers: [
provideExperimentalZonelessChangeDetection(),
]});
NgModule Bootstrap
platformBrowser().bootstrapModule(AppModule);
@NgModule({
providers: [provideExperimentalZonelessChangeDetection()]
})
export class AppModule {}
Removing ZoneJS
To remove ZoneJS from an Angular project:
Remove
zone.js
andzone.js/testing
from theangular.json
polyfills.If using
polyfills.ts
, delete:
import 'zone.js';
import 'zone.js/testing';
- Uninstall ZoneJS from dependencies:
npm uninstall zone.js
Requirements for Zoneless Compatibility
Angular determines when to run change detection through specific notifications, such as:
-
ChangeDetectorRef.markForCheck
(automatically triggered byAsyncPipe
) ComponentRef.setInput
- Updating a signal referenced in a template
- Template event listeners
- Attaching views marked as dirty
OnPush-Compatible Components
Using ChangeDetectionStrategy.OnPush
is recommended for compatibility. While not mandatory, it ensures Angular efficiently detects updates without relying on ZoneJS.
Removing Incompatible NgZone Features
The following APIs do not work in zoneless mode and should be removed:
NgZone.onMicrotaskEmpty
NgZone.onUnstable
NgZone.isStable
NgZone.onStable
Replace them with:
-
afterNextRender()
for single change detection waiting -
afterRender()
for conditions spanning multiple cycles -
MutationObserver
for direct DOM state monitoring
Note: NgZone.run
and NgZone.runOutsideAngular
are still supported.
PendingTasks for Server-Side Rendering (SSR)
ZoneJS helps determine when SSR should serialize the page. Without ZoneJS, use the PendingTasks
service to track async tasks:
const taskService = inject(PendingTasks);
const taskCleanup = taskService.add();
await doSomeWorkThatNeedsToBeRendered();
taskCleanup();
Angular uses this internally for routing and HTTP requests.
Testing and Debugging
Using Zoneless in TestBed
To test a zoneless Angular app:
TestBed.configureTestingModule({
providers: [provideExperimentalZonelessChangeDetection()]
});
const fixture = TestBed.createComponent(MyComponent);
await fixture.whenStable();
Avoid fixture.detectChanges()
to mimic real-world change detection.
Debug Mode for State Updates
Use provideExperimentalCheckNoChangesForDebug()
to catch undetected updates. Angular will throw ExpressionChangedAfterItHasBeenCheckedError
if a binding changes without notification.
By following these steps, you can successfully migrate your Angular app to a zoneless architecture, improving performance and maintainability.
Feel free to explore the GitHub repository for more details and to try out the project yourself. Happy coding!
Top comments (0)