The web framework extends the standalone API and, as the biggest innovation, brings a new directive called NgOptimizedImage.
The current main version, Angular 14, brought standalone components with it for the first time, which made the use of NgModule optional. Almost three months after the release, Angular 14.2 was released as the second minor version and extends the standalone API to include the router. As the biggest change, however, the release brings a new directive under the name NgOptimizedImage
With.
Image best practices
Optimizing the bundle size – the bundle is the JavaScript file(s) of the front-end application – is a very time-consuming and demanding activity for developers. But the smaller the file, the faster the application can be started in the browser.
It should be noted that a browser does not only load JavaScript files. Images, especially full-screen ones, can make up multiples of a bundle. This is particularly painful when the image in question is not even in the viewport and is therefore not needed for the initial loading.
Here comes the new directive NgOptimizedImage
in the game. To activate it is in <img>
the attribute src
through rawSrc
exchange.
<!-- ohne NgOptimizedImage -->
<img [src]="'/assets/' + holiday.imageUrl" [alt]="holiday.title" />
<!-- mit NgOptimizedImage -->
<img [rawSrc]="'/assets/' + holiday.imageUrl" [alt]="holiday.title" />
Listing 1: Activation of NgOptimizedImage
With Listing 1, the new directive already carries out various checks. Should the attributes for width
or height
are missing, the picture is not displayed, but an error message appears. The omission of the dimension information leads to the so-called content shifting or cumulative layout shift (CLS) according to Core Web Vitals. The layout is shifted by the subsequent loading of the images. This is not a good user experience and can be easily avoided by setting the attributes.
Furthermore, each image is loaded lazy by default. That is, the browser knows that the developers do not count the image among the critical elements. This can mean that images located far outside the viewport are only loaded when required.
In the example used, this behavior can be displayed via the network tab in the DevTools. Only the first three out of ten images are loaded. The browser only reloads when you scroll down.
Priority loading and CDN
Best practices require that the “critical images” that reside in the viewport be identified via the attribute priority
to be marked as such. However, if you forget to do this, the directive with a warning message will also help in this case. However, it is only used during development mode (ng serve
) shown.
@Component({
template: `<div *ngFor="let holiday of holidays; first as isFirst">
<h3>{{ holiday.title }}</h3>
<img
[rawSrc]="'/assets/' + holiday.imageUrl"
[alt]="holiday.title"
[priority]="isFirst ? 'priority' : 'false'"
width="1920"
height="1080"
/>
</div>`,
imports: [NgForOf, NgOptimizedImage],
standalone: true,
})
export class OptimizedComponent {
// ...
}
Listing 2: Standalone component with NgOptimizedImage that prioritizes the first image
There is also the option of specifying Content Delivery Networks (CDN) that automatically provide image scaling. This can be set in Angular using a loader function. Again, Angular ensures that the CDN URL with preconnect
has been set. If not, a warning message appears again.
@Component({ template: `
Optimized Version with Cloudinary CDN
{{ holiday.title }}
< img [rawSrc]=”‘/angular-14-2/’ + holiday.imageUrl” [alt]=”holiday.title” [priority]=”isFirst ? ‘priority’ : ‘false'” width=”1920″ height=”1080″ />
`, imports: [NgForOf, NgOptimizedImage]providers: [provideCloudinaryLoader(” standalone: true, }) export class CdnComponent { holidays = holidays; }
Listing 3: Komponente mit Bildern von Cloudify
Vor allem für Angular-Anwendungen, die sehr stark mit Bildern arbeiten, ist diese neue Direktive ein wahrer Segen. In den nächsten Releases sollen weitere Features folgen.
Router als Standalone API
Neben der neuen Direktive bringt Angular 14.2 auch Standalone APIs. Standalone Components (mit Pipes und Directives) tragen bekanntlich durch das Weglassen von NgModules zu einer Verringerung des Boilerplate-Codes bei. Es ist zwar schön, seinen eigenen Code ohne NgModules schreiben zu können, man trifft sie aber immer dann an, wenn man Funktionen des Frameworks wie RouterModule
, ReactiveFormsModule
, HttpClientModule
oder Drittbibliotheken verwendet.
Die Standalone API schickt sich an, Alternativimplementierungen zu den NgModule-basierten Funktionen anzubieten.
Mit Angular 14.2 wurde das RouterModule
samt Direktiven zu Standalone migriert. Das heißt, es ist jetzt nicht mehr notwendig, bei der Konfiguration der Routen RouterModule.forRoot
oder forChild
zu verwenden. Als Alternative gibt es die Funktion provideRouter
.
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
importProvidersFrom(
BrowserAnimationsModule,
// RouterModule.forRoot(routes), <-- durhc provideRouter (oben) ersetzt
HttpClientModule
),
]});
Listing 4: The provideRouter function in use
The directives associated with routing such as routerLink
is now available as a standalone version. You can now, with appropriate use, instead of the RouterModule
easy RouterLinkWithHref
in the imports
Add and the directive is ready to use.
@Component({
template: `<ul>
<li>
<a mat-raised-button routerLink="/optimized">Optimized</a>
</li>
</ul> `,
styleUrls: ["./sidemenu.component.scss"],
standalone: true,
imports: [CommonModule, MatButtonModule, RouterLinkWithHref],
})
export class SidemenuComponent {}
Listing 5: Component with standalone routerLink
A round release
All in all, Angular 14.2 is a well-rounded affair and contains above all NgOptimizedImage
new features on a scale that you didn’t even have with previous major releases. An upgrade is therefore worthwhile in any case.