DEV Community

Fábio Englert Moutinho for Bitovi

Posted on • Originally published at bitovi.com

Improve App Performance with the NgOptimizedImage Directive

Newly released Angular 14.2 comes with a nifty image optimization feature that can be used to improve the performance of your application.

In this blog post, we will take a look at the exciting new NgOptimizedImage directive and explain how we used it to make this example e-commerce application perform up to 50% better on Lighthouse scores!

image showing improved lighthouse score of Angular e-commerce app after implementing NgOptimizedImage

What is NgOptimizedImage?

NgOptimizedImage is a Directive focused on improving Image Loading performance. As a happy side-effect, NgOptimizedImage enforces best practices and improves Core Web Vitals scores, which might help your application rank higher on search engines.

Important Note: NgOptimizedImage is on Developer Preview. Features on Developer Preview might change APIs without notice. If you decide to use NgOptimizedImage on production, be aware when updating your application.

How to Use NgOptimizedImage

In order to use the NgOptimizedImage directive, identifiable by the selector img[rawSrc], you need to import NgOptimizedImage into your Module or Standalone Component.

import { NgOptimizedImage } from '@angular/common';
Enter fullscreen mode Exit fullscreen mode

Set Up an Image Loader

Image Loaders are tools that host images and provide optimization services such as image resizing or compression.

Angular now provides popular Image Loader configurations out of the box. In our e-commerce application example, we set up ImageKit with the provideImageKitLoader function, whose path argument is the default URL endpoint for an account.

// src/app/app.module.ts

// ... other imports
import { NgOptimizedImage, provideImageKitLoader } from '@angular/common';

@NgModule({
  declarations: [AppComponent, HomeComponent, CartComponent],
  imports: [BrowserModule, AppRoutingModule, ScullyLibModule, NgOptimizedImage],
  providers: [provideImageKitLoader('https://ik.imagekit.io/fabioemoutinho')],
  bootstrap: [AppComponent],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Understand NgOptimizedImage Properties

NgOptimizedImage adds additional properties to an img tag:

  • rawSrc: string: instead of src full URL, rawSrc represents the source image name

  • rawSrcset: string: a comma-separated list of width or pixel density descriptors. Not required, but recommended. Usually used in conjunction with sizes attribute if you want to provide different image sources for different viewport sizes.

    <!-- example taken from https://angular.io/api/common/NgOptimizedImage#properties -->
    
    <img rawSrc="hello.jpg" rawSrcset="100w, 200w" />
    
    <!-- img tag above would output an img tag similar to the img below -->
    <img src="path/hello.jpg" srcset="path/hello.jpg?w=100 100w, path/hello.jpg?w=200 200w" />
    
  • priority: boolean: defaults to false; If true, adds multiple optimizations to the image

Images are going to be lazy-loaded by default. That is, it is going to be up to the browser to decide when to load the images. While lazy-loading an image is usually a good approach, in some cases, like when you want to make sure the browser will download critical images first, you might want to set the priority property to true in order to increase the performance of your app.

The NgOptimizedImage directive also expects every image to have explicit height and width attributes.

Here are the changes we had to make on a component’s template to use the NgOptimizedImage directive.

  <!-- src/app/home/home.component.html ‐‐>

  <picture class="picture block relative overflow-hidden">
    <img
-     [src]="product.image"
+     [rawSrc]="product.id + '.jpg'"
      [alt]="product.title"
      class="img not-loaded object-contain w-full h-full absolute top-0 left-0"
      (load)="onLoadImage($event)"
      (error)="onErrorImage($event)"
+     width="200"
+     height="200"
    />
  </picture>
Enter fullscreen mode Exit fullscreen mode

Performance Results

In our example application, we removed scully to better measure the impact of a vanilla implementation of the NgOptimizedImage directive on the application’s home page. We tested two different scenarios:

  1. https://e-commerce-no-scully-example-angular-13.vercel.app/ - Angular 13.3.11
  2. https://e-commerce-no-scully-example.vercel.app/ - Angular 14.2.0, using NgOptimizedImage

We then ran Lighthouse locally (desktop) and had the following results:

Metric Angular 13.3.11 Angular 14.2 with NgOptimizedImage Impact
First Contentful Paint 0.4 s 0.3 s 25% decrease
Speed Index 1.2 s 0.6 s 50% decrease
Largest Contentful Paint 1.7 s 1.0 s 41% decrease
Time to Interactive 0.5 s 0.4 s 20% decrease
Total Blocking Time 0 ms 0 ms -
Cumulative Layout Shift 0.003 0.003 -
Performance 93 99 6.45% increase

Even though you get excellent performance results with the automatic lazy loading of images, NgOptimizedImage shines even brighter when combining the usage of image loaders with the rawSrcset property and sizes attribute. Implementing the rawSrcset property and sizes attribute enables you to further optimize your application for different devices, especially for mobile devices.

What’s Next for Angular’s Image Directive?

Chrome’s blog post announcement about NgOptimizedImage directive presents an interesting roadmap, and we can expect many improvements like automatic srcset and sizes attributes for responsive images, automatic height and width attributes and more.

Angular v14.2 introduces other interesting features that we will talk about next, stay tuned on Bitovi's Twitter.

Need help staying up to date with the latest version of Angular to take advantage of these cool new features? Contact us for Angular Consulting help!

Top comments (0)