
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
This project aims to remove zone.js by using JavaScript Proxies and the Angular's new inject function to get the ChangeDetectorRef of the component and notify when properties are changed.
Thus, you can remove zone.js from your project and both improve the performance of your application and the bundle size.
Just install with npm:
npm install zoneless
import { useState } from 'zoneless';
@Component({
selector: 'app-root',
template: `
<h1>Zoneless</h1>
<p>Counter: {{ state.counter }}</p>
<button (click)="increment()">Increment</button>
`,
})
})
export class AppComponent {
state = useState({
counter: 0,
});
increment() {
this.state.counter++; // everything works as usual
}
}
zone.jsFirst, you need to remove zone.js from your polyfills. Starting from Angular 15, polyfills are loaded using a property in angular.json:
"projects": {
"my-project": {
"architect": {
"build": {
"options": {
"polyfills": [
"zone.js" // remove this line
]
}
}
}
}
}
And disable using ngZone in main.ts:
platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' })
That's it, now you have a zoneless application!
You can also use computed properties, derived from an existing state:
import { useState, computed } from 'zoneless';
@Component({
selector: 'app-root',
template: `
<h1>Zoneless</h1>
<p>Counter: {{ state.counter }}</p>
<p>Counter * 2: {{ doubleCounter() }}</p>
<button (click)="increment()">Increment</button>
`,
})
})
export class AppComponent {
state = useState({
counter: 0,
});
doubleCounter = computed(
() => this.state.counter * 2,
() => [this.state.counter],
);
increment() {
this.state.counter++; // everything works as usual
}
}
Notice two things:
computed function takes a function as the first argument, which is the function that will be called to get the value of the computed property.Observable-sasync pipe might no longer work, but instead, you can use another function provided by the library, useObservable:
import { useObservable } from 'zoneless';
@Component({
selector: 'app-root',
template: `
<h1>Zoneless</h1>
<p>Timer: {{ interval() }}</p>
`,
})
})
export class AppComponent {
state = useObservable(interval(1_000));
}
So we no longer need the async pipe, but we can still use Observable-s.
Note that the
useObservablefunction returns a function, so you need to call it to get the value. This is to make Angular's change detection actually know the value has changed.
The useObservable function also automatically unsubscribes from the Observable when the component is destroyed.
No issues have been reported as of now, but this is experimental, so use at your own risk.
Any contribution is welcome, be it a comment, and open issue, PR or anything else. As mentioned before, this is experimental, so any feedback is welcome. The aim is to experiment this further and see if it can be used in production.
FAQs
## Purpose
We found that zoneless demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.