written for coders favicon image

Angular 15 is released, Learn about everything new!

Image for Angular version 15 release blog post

The new Angular version 15 is packed with awesome new features and performance improvements! Standalone components have been moved over to the stable Angular API, directive composition API is added, Angular image directive for better performance, and much more cool stuff in this Angular release. In this blog post, we will explain everything that is new in Angular 15 so without further ado, let's get started!

Table of content:

Angular 15

Over the past year, the Angular team removed the legacy compiler and rendering pipeline of the framework which enabled them to make a series of improvements to benefit the performance and developer experience. That is also where to focus of the new Angular V15 lies, improvements for an easier and better development flow paired with performance improvements to decrease bundle sizes and load times.

What is new in Angular 15?

  • Angular standalone components are now in the stable API surface

  • Tree-shakable API for standalone components and the HttpClient

  • Directive composition API

  • Image directive is out of developer preview

  • Functional route guards

  • Router unwraps default imports automatically

  • Improved stack tracing

  • Improvements in experimental ESBuild support

  • CLI Improvements

Angular standalone components are stable!

In Angular version 14, the team introduced standalone components which enable developers to create standalone components, directives, and pipes omitting the need for NgModules. In Angular 14 the standalone components were still in developer preview. Now in Angular 15, the team has happily announced the standalone components API has moved from developer preview to the stable surface of the framework.

To make the standalone components part of the stable part of the Angular framework the team needed to ensure the standalone components work throughout the framework. In Angular 15 the standalone components fully work in the HttpClient, Angular Elements, router, and more!

With the standalone API you can now bootstrap your Angular application using a single component instead of a module.

Gist

Tree-shakable routes with standalone API

With the new improvements to the Angular router, you can now build multi-route applications with standalone components. Start by declaring your root route like this:

Gist

Next, you need to declare the lazy routes we import in the above code snippet. To do this create a new file and declare an array with the lazy routes you want to load. Note the routes you load here need to be standalone components as well. The router will la

Gist

Lastly, we need to add the routes to our bootstrapApplication function call. Here we register the routes inside the providers array.

Gist

By using this routing strategy and the provideRouter API you get another great advantage. The new router can tree-shake the standalone routes and reduce the bundle size of your application. By tree-shaking, the unused code from the router module gets removed from your application bundle. The Angular team ran several experiments and found an 11% reduction in the router code in the bundle!

Directive composition API

Angular directive composition is an entirely new feature for the Angular framework and brings code reuse to a new level! It was inspired by one of the most popular feature requests on Github, so if you have a great new feature in mind for the Angular framework don't be afraid and post it on Github, the team might just include your request!

The directive composition API opens up a brand new code-reusing strategy by enabling developers to add directives to host elements. Meaning you can add a directive in the components decorator instead of the HTML template. Note that the directive composition API can only be used in combination with a standalone component. An example of an implementation would look like this:

Gist

In the code snipped above the MatMenu component is equipped with 2 directives HasColor and CdkMenu. This works as a sort of inheritance and now the inputs, outputs, and logic of the directives are added to the MatMenu component. We can use the inputs and outputs of the directive on the HTML tag like this:

Gist

As you can imagine this opens up a whole new way of reusing code and inheriting logic, styling, and behavior for your components.

The image directive is out of preview!

The Angular team first introduced the Image directive in Angular V14.2 and is now happy to announce the Image directive made it into the stable API of the Angular framework. The Image directive is made in collaboration with Chrome Aurora and it is designed to improve your LPC (Largest Contentful Paint).

In Angular 15 the Image directive receives a few new features:

  • Automatic srcset generation: The image directive makes sure the correct sizes are requested when generating the image by generating the srcset attribute for you. Having the correct dimensions on your images can help to improve the load time. It also prevents layout shifting giving your users a better experience

  • Fill mode [experimental]: this fill mode causes the image to fill its parent container, because of this you do not have to set the width and height properties on the image tag. It’s a useful tool if you’d like to migrate CSS background images to use the directive or when you don't know the sizes of your images.

The NgOptimizedImage directive can be used in standalone components or NgModules by adding NgOptimizedImage to the imports array or the component or module. You can use the directive in your HTML templates by changing the SCR attribute to ngSrc and adding a priority attribute like this:

<img ngSrc="cat.jpg" width="400" height="200" priority>

For more details and information on the IMage directive, you can read the official Angular documentation.

Functional route guards

Besides the tree-shaking in the standalone router API, the Angular team also worked on reducing the boilerplate needed to create route guards. With the introduction of functional route guards, they did a stellar job and we can now create guards with barely any boilerplate. Below is an example of a route guard where we check if the user is logged in. In the below example, you can see we perform barely any logic but still need a lot of boilerplate code to create the route guard.

Gist

With the new functional route guards, you can write your guard directly in the routes array with barely any code needed. Below is an example of the same guard written as a functional guard:

Gist

Now the entire guard is expressed inside the route declaration. Functional guards are also composable, meaning you can create factory-like functions that accept a configuration and return a guard or resolver function.

Router unwraps default imports automatically

To further reduce the boilerplate code in the router-related code and make lazy-loaded routes easier to configure, the Angular router now automatically unwraps default imports when lazy loading routes. Let's say we have a standalone component we want to lazy load before the change we had to do it like this:

{ path: 'lazy', loadComponent: () => import('./lazy-file').then(m => m.LazyComponent), }

Now in Angular 15 the standalone router API automatically unwraps the LazyComponent for you and because of that we can reduce your code down to this:

{ path: 'lazy', loadComponent: () => import('./lazy-file'), }

Improved stack traces

If you have ever worked on an Angular app you probably encountered a bug where you wanted to check the stack trace to locate where your bug originated and what code was called beforehand. But there were two main problems here...

  1. There was only 1 line in the stack trace referring to code we write ourselves, the rest are third-party dependencies like Angular framework, Zone.js, RxJS, and so on

  2. There was no information on what user action triggered the error

Together with the Angular DevTools team, the stack trace for Angular has been improved drastically! The new stack trace output for errors now looks like this:

ERROR Error: Uncaught (in promise): Error Error at app.component.ts:18:11 at fetch (async) at (anonymous) (app.component.ts:4) at request (app.component.ts:4) at (anonymous) (app.component.ts:17) at submit (app.component.ts:15) at AppComponent_click_3_listener (app.component.html:4)

As you can see the error was triggered by a click event in the 4th line of the HTML in the app component. Furthermore, we see a lot more useful information in the stack trace and that makes debugging your Angular application much easier!

Improvements in the experimental esbuild support

In Angular 14 the team announced the experimental support for esbuild in ng build. The support for esbuild will speed up your build times and simplify your pipelines.

In Angular 15 the team added experimental Sass, SVG template, file replacement, and ng build --watch support! You can give esbuild a try by updating your builders angular.json from:

"builder":"@angular-devkit/build-angular:browser"

To:

"builder":"@angular-devkit/build-angular:browser-esbuild"

Angular CLI improvements

The Angular CLI now allows you to create standalone components with the --standalone flag.

ng g component --standalone

The Angular team also working to simplify the output of ng new. As a first step they reduce the configuration by removing test.tspolyfills.ts, and environments. You can now specify your polyfills directly in angular.json in the polyfills section.

Make your friends more educated by sharing!