Optimizing with Nuxt Image

Apr 30, 2023·

Web performance optimization has always been a challenging but very interesting task for me, and with the introduction of Core Web Vitals, things have never been simpler.

Of the three metrics to optimize for, Largest Contentful Paint (LCP) has always proved to be the most difficult. LCP measures the loading speed of the largest element on a webpage, which is typically an image or video. A poor LCP score can negatively impact user experience and search engine rankings.

PageSpeed Insights is a popular tool for analyzing web page performance. It provides suggestions for improving load times and optimizing the LCP metric — including compressing images, using modern formats like WebP, and optimizing for different screen sizes with the srcset attribute.

In the initial rebuild of the Ogre Cave, following these recommendations gave me pretty good results. I manually converted images to WebP and created multiple versions for different screen sizes using srcset.

pagespeed_v0

Figure 1: Using native <img> tag pagespeed recommendations

The results were good but the process was not. It was unwieldy, time-consuming, and unsustainable at scale.

I have a couple of past and ongoing projects where this wasn't even feasible — the content creators and developers weren't from the same team.

The Solution: Nuxt Image

Nuxt Image is a powerful image optimization module for Nuxt.js, the framework behind this site and most of my recent projects. With Nuxt Image, I can easily optimize images for different screen sizes and formats, including WebP. It automatically generates multiple versions and serves the right one based on the user's device and screen size.

Nuxt Image also offers some useful extras. It supports lazy-loading, which loads images only when they become visible on screen, and progressive image loading, which shows a low-quality placeholder while the full image loads in the background.

Installing Nuxt Image

Like most Nuxt modules, installation is straightforward. You can install it as a dev dependency using yarn, npm, or in my case pnpm.

pnpm i -D @nuxt/image-edge

Then add it to the modules section in nuxt.config:

export default defineNuxtConfig({
  // ...
  // modules: ['@nuxt/image-edge']
  // ...
})

<nuxt-img> is a drop-in replacement for the <img> tag, so adopting it is easy.

Using Nuxt Image

The real power comes from using its props effectively. There's a complete properties reference available, but these are the ones I use most:

  1. Prioritize image loading with preload.
  2. Resize your static images with width and height.
  3. Resize responsive images with sizes. This sets up both sizes and srcset in the generated <img>.
  4. Reformat images with format. Dynamically convert your jpg to webp.

Results

Manual image optimization is tedious. Nuxt Image simplifies the process and handles most of it automatically.

Refactoring the Ogre Cave over a weekend not only simplified my code — it also cleaned up my image directory of all the manually generated variants.

And as a bonus, the latest PageSpeed Insights run showed some unexpected but very welcome improvements in Ogre Cave's performance.

pagespeed_v2

Figure 2: Optimized with <nuxt-img> tag