Hey there,
I know I am a little late at this point. Also It has been a long since I have posted something here. So here it goes.
Version 16.0.0 is here and it has some great updates for Angular developers everywhere. 🎉🎉
TL;DR 🙌
✅ New reactivity model
✅ Angular Signals
✅ Server-side rendering and hydration
✅ Improved tooling for standalone components, directives, and pipes
✅ Advancing developer tooling
✅ Improving Developer Experience
How to update to version 16
Visit update.angular.io for detailed information and guidance. To have the best update experience,
Update to 16
ng update @angular/cli @angular/core
In order to update your global angular,
npm i -g @angular/cli
What’s in this release?
✅ New reactivity model
- As part of the v16 release Angular team share a developer preview of a brand new reactivity model for Angular which brings significant improvements to performance and developer experience
- It’s entirely backward compatible and interoperable with the current system, and enables:
- Better run time performance by reducing the number of computations during change detection.
- Brings a simpler mental model for reactivity
👉 Signals
- The Angular signals library allows you to define reactive values and express dependencies between them.
- A signal is a value with explicit change semantics.
- In Angular a signal is represented by a zero argument getter function returning the current signal value:
- Signals are fundamentally read-only: we can ask for the current value and observe change notification.
@Component({
selector: 'my-app',
standalone: true,
template: `
{{ fullName() }} <button (click)="setName('John')">Click</button>
`,
})
export class App {
firstName = signal('Jane');
lastName = signal('Doe');
fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
constructor() {
effect(() => console.log('Name changed:', this.fullName()));
}
setName(newName: string) {
this.firstName.set(newName);
}
}
- The snippet above creates a computed value fullName, which depends on the signals firstName and lastName.
- We also declare an effect, which callback will execute every time we change the value of any of the signals it reads — in this case fullName, which means it transitively also depends on firstName and lastName.
- When we set the value of firstName to ”John”, the browser will log into the console:
"Name changed: John Doe"
✅ Server-side rendering and hydration
- In the new full app non-destructive hydration, Angular no longer re-renders the application from scratch.
- Instead, the framework looks up existing DOM nodes while building internal data structures and attaches event listeners to those nodes.
-
Features
- No content flickering on a page for end users
- Better Web Core Vitals in certain scenarios
- Future-proof architecture that enables fine-grained code loading with primitives
- Easy integration with existing apps
- Incremental adoption of hydration with the
ngSkipHydration
attribute in templates for components performing manual DOM manipulation
- Non-destructive hydration is still at the developer preview stage.
- But you can enable it by adding provideClientHydration() as a provider when bootstrapping the application.
import {
bootstrapApplication,
provideClientHydration,
} from '@angular/platform-browser';
...
bootstrapApplication(RootCmp, {
providers: [provideClientHydration()]
});
- You can find more details on how it works in the documentation right here 👉 Hydration.
✅ Improved tooling for standalone components, directives, and pipes
- Angular 14 started supporting standalone components, which are independent of modules.
- Angular 16 takes this to the next level by supporting standalone project creation.
ng new --standalone
- You’ll get a simpler project output without any NgModules.
- Additionally, all the generators in the project will produce standalone directives, components, and pipes!
- Zone.js can be configured with the new bootstrapApplication API.
bootstrapApplication(App, {
providers: [provideZoneChangeDetection({ eventCoalescing: true })]
});
✅ Advancing developer tooling
👉 Developer preview of the esbuild-based build system
- In
ng serve
angular now using Vite for the development server, and esbuild powers both development and production builds - Angular CLI relies on Vite exclusively as a development server.
- To support selector matching, the Angular compiler needs to maintain a dependency graph between components which requires a different compilation model than Vite.
- You can give Vite + esbuild a try by updating your angular.json:
...
"architect": {
"build": { /* Add the esbuild suffix */
"builder": "@angular-devkit/build-angular:browser-esbuild",
...
👉 Better unit testing with Jest and Web Test Runner
- Jest is one of the most loved testing frameworks and test runners.
- Experimental Jest support is added with Angular 16.
Planning to move all the existing Karma projects to Web Test Runner in future updates.
You can experiment with Jest in new projects by installing Jest with
npm install jest --save-dev
and updating your angular.json file
{
"projects": {
"my-app": {
"architect": {
"test": {
"builder": "@angular-devkit/build-angular:jest",
"options": {
"tsConfig": "tsconfig.spec.json",
"polyfills": ["zone.js", "zone.js/testing"]
}
}
}
}
}
}
More unit testing strategies can be found right here 👉 Blog Post
👉 Autocomplete imports in templates
- The language service now allows auto-import components and pipes.
- In v16
TypeScript 5.0
support is added, with support forECMAScript decorators
, removing the overhead ofngcc
, adding support forservice workers
and app shell in standalone apps, expanding CSP support in the CLI
✅ Improving Developer Experience
👉 Required inputs
- In Angular 16, you can now define input values as required.
- You can either use the @Input decorator or the @Component decorator inputs array to define one.
@Component(...)
export class App {
@Input({ required: true }) title: string = '';
}
Passing router data as component inputs
- Now you can pass the following data to a routing component’s inputs
- Route data — resolvers and data properties
- Path parameters
- Query parameters *
const routes = [
{
path: 'about',
loadComponent: import('./about'),
resolve: { contact: () => getContact() }
}
];
@Component(...)
export class About {
// The value of "contact" is passed to the contact input
@Input() contact?: string;
}
- You can enable this feature by using withComponentInputBinding as part of the provideRouter.
👉 CSP support for inline-styles
- The ngCspNonce attribute is useful if you have access to server-side templating that can add the nonce both to the header and the index.html when constructing the response.
<html>
<body>
<app ngCspNonce="{% nonce %}"></app>
</body>
</html>
👉 Self-closing tags
- A highly requested feature we recently implemented allows you to use self-closing tags for components in Angular templates
<super-duper-long-component-name [prop]="someVar"/>
For more let us hear it from the creators
Credits : Official Announcement 😄
Changelog : Repository
Top comments (0)