Posted on May 22, 2023
Angular version 16 has major changes that will greatly impact Angular's future, popularity, and the lives of Angular developers! There's no denying that every new version of Angular introduces many exciting features, and Angular 16 will be no different. Angular is undergoing a sort of revival, and version 16 marks just the initial stage of this resurgence. Here are some notable transformations that can be expected in this release. 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. It means that end user-facing applications where initial time and SEO are very important, could leverage the SSR with hydration. With Angular universal application, angular would now enable real non-destructive server-rendered applications. What is hydration? Hydration is the process that restores the server-side rendered application on the client. This includes things like reusing the server-rendered DOM structures, persisting the application state, transferring application data that was retrieved already by the server, and other processes. Why is hydration important? Hydration improves application performance by avoiding extra work to re-create DOM nodes. Instead, Angular tries to match existing DOM elements to the structure of the application at runtime and reuses DOM nodes when possible. What are the advantages? To get started it is as easy as adding a few lines to your main.ts: We will discuss more about these in our next blog Server-side rendering (SSR) and hydration in Angular v16 Note: Without hydration enabled, server-side rendered Angular applications will destroy and re-render the application's DOM, which may result in a visible UI flicker. A brand new reactivity model of Angular which will help to improve performance and developer experience, is compatible with the current system. Now the big question is why? Angular discovered that scaling out Zone.js did not yield optimal solutions. Let's figure out why is that? Currently, all change detection is managed and performed under the hood of the Zone.js library and triggering a change detection by listening to any event in the browser, so it is natural that if something is in one of the child components then the whole tree of dependencies will be re-evaluated. Even if your application's change detection is in OnPush mode, the change detection cycle will go through the entire tree, unlike the default mode, OnPush components with no change dependencies will not be re-evaluated. Therefore it is clear that the change of detection in Angular is not optimal and in order to solve this problem that the integration of Signal will help. The concept of Signal has been embraced and effectively implemented in various frameworks such as Preact, Solid, and Vue for quite some time, and has a lot of good performance improvement. With Signal, the change detection level is done at the level of the signal variable. Thus a change detection will be done at the component level only, it does not require traversing through the whole tree without the need for the Zone.js. Signals will Significantly improve interoperability with reactive libraries such as RxJS. Note: In the future, Zone Js could be optional Three reactive primitives - It helps to tell UI what data changes and when, It helps your application UI Sync with your data. We will discuss more about these in our Angular v16 Signals - The New Reactivity Model To change the value of a writable signal, you can either .set() it directly: There is By utilizing this functionality, the component will have direct access to the router data mentioned, making it unnecessary to retrieve these values using Current Approach New approach The angular version now supports an optional new development server that is called Vite. Its Pre-bundling with Vite's ESbuild makes it 10 to 100 times faster than using any other JS bundler. This is because it helps improve page speed and convert CommonJS / UMD modules to ESM. To enable this we need to change angular.json Vite uses HMR functionalities to keep track of changes in your application without reloading the full page. With the HMR API, the browser will only load the modified section of the page and still retain the application's state. New DestroyRef injector 😮 In Angular v16, a new provider called DestroyRef has been introduced. This provider enables the registration of destroy callbacks for a specific lifecycle scope.Non-Destructive Hydration With Server-Side Rendering 😱
import {
bootstrapApplication,
provideClientHydration,
} from '@angular/platform-browser';
...
bootstrapApplication(RootCmp, {
providers: [provideClientHydration()]
});
Angular Reactivity 😕
const count = signal(0);
// Signals are getter functions - calling them reads their value.
console.log('The count is: ' + count());
count.set(3);
.update()
and .mutate()
which will help signal variables to compute.
firstName = signal('Jane');
lastName = signal('Doe');
fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
effect(()=> {
localStorage.setItem('FullName', this.fullName());
});
Improved tooling with Standalone Schematics
ng new great-app --standalone
//OR
ng generate @angular/core:standalone
//OR
ng new --standalone
Router Update 😍
ActivatedRoute
. Instead, we can simply utilize inputs
.@Component({
...
})
class SomeComponent {
constructor(route: ActivatedRoute) { }
data = this.route.snapshot.data['dataKey'];
params = this.route.snapshot.params['paramKey']
}
@Component({
...
})
class SomeComponent {
@Input() dataKey: string;
@Input() paramKey: string;
//or
@Input() set dataKey(value: string){
//react to the value
};
@Input() set paramKey(value: string){
//react to the vaue
};
}
New Development Server (Vite) + esbuild 🤩
...
"architect": {
"build": { /* Add the esbuild suffix */
"builder": "@angular-devkit/build-angular:browser-esbuild",
...
Other updates to Angular v16 😄
@Input({ required: true }) name!: string;
NavigationEnd
the routerEvent
property now also accepts type NavigationSkipped
@Component({
selector: 'foo',
standalone: true,
template: '',
})
class FooComponent {
constructor() {
inject(DestroyRef).onDestroy(() => {
// do something when the component is destroyed
})
}
}
Karma
to Web Runner Tool
😫NgOptimizedImage
: Directive that improves image loading performance by enforcing best practices. 😄