Next.js 10 Image Optimisation Component and next-optimized-images, a brief comparison
Tags: react, javascript, webdev, nextjs
Published: 2020-10-28 15:31:23

*Edit: Since writing this blog I've been able to try the built in Next.js Image optimisation. I found that due to the requirements of either having to specify a `width` and `height` or use `layout="fill"` and a parent component to size the images, it was impossible to allow my image to be dynamically resized by the height of it's container e.g. no more `height="100%"`. [This requirement seems to be causing issues to other peoples projects as well](https://github.com/vercel/next.js/discussions/18739#discussioncomment-121272). Hopefully they will fix it in the future! For now, I'll be sticking with `next-optimized-images`*

[Next.js 10 was released yesterday](https://nextjs.org/blog/next-10) as part of the first ever [Next.js Conf](https://nextjs.org/conf), an interactive online experience consisting of various talks centred around all things Next.js.

One groundbreaking feature announced as part of version 10 is the all new [Image Component and Automatic Image Optimisation](https://nextjs.org/blog/next-10#built-in-image-component-and-automatic-image-optimization). The Image Component is designed to be a drop in replacement for existing `<img>` elements and when used will:

1. Reduce the size of your image.
2. Optimise it for various viewpoints such as desktop and mobile screens.
3. Lazy load images so that ones further down the page are loaded later and ones at the top are prioritised.
4. Where possible, convert your image to next generation formats such as WebP (30% smaller than JPEG).

These optimisations add up and have the potential to make a website much faster just by changing an `<img>` to an `<Image>`.

Some interesting figures about Image Optimisation from the Next.js 10 blog:
* "**Images take up 50%** of the total bytes on web pages".
* "Half of all images are over one megabyte in size".
* "Users browse the web using their phones, tablets, and laptops, yet images are still as a one size fits all. For example: sites load a **2000 by 2000** pixel image, but phones are only displaying it as **100 by 100** pixels".
* "**30%** of images on web pages are outside of the initial viewport, meaning the browser loads images that a user does not see until they scroll further down the page".
* "**99.7% of images** on websites don't use modern image formats like WebP".
* "WebP ... is about 30% smaller than JPEG".

[*Read the full blog post on nextjs.org*](https://nextjs.org/blog/next-10#built-in-image-component-and-automatic-image-optimization)

**If you've read this far I know what you're thinking... hasn't this already been done?**

And the answer is, sort of...

## Enter [next-optimized-images](https://github.com/cyrilwanner/next-optimized-images)

Next-optimized-images is a Next.js plugin which, as the name suggests, automatically optimises your images.

I've been using it for a couple of years and first came across it when I was building https://artistjodi.com, a website for a client that contains an almost ridiculous number of images, and it saved me from either having to manually compress each image or building a script to do it. The point is it saved me hours and gave me features I didn't even know I needed.

Next-optimized-images states that it will:
* Reduces image size by optimizing images during build (20-60%)
* Improves loading speed by providing progressive images (for formats that support it)
* Inlines small images to save HTTP requests and additional roundtrips
* Adds a content hash to the file name so images can get cached on CDN level and in the browser for a long time
* Same image URLs over multiple builds for long time caching
* Provides query params for file-specific handling/settings
jpeg/png images can be converted to webp on the fly for an even smaller size
* Provides the possibility to use SVG sprites for a better performance when using the same icons multiple times (e.g. in a list)
* Can resize images or generate different placeholders while lazy loading images: low quality images, dominant colors or image outlines

[*From the GitHub repository*](https://github.com/cyrilwanner/next-optimized-images)

This sounds familiar to the Next.js `Image` component. In fact, on its canary branch (version 3) it has it's own Image component. Let's look at the differences on paper.

### Quick look differences

| Feature | Next.js Image Optimisation | next-optimized-images |
| --------- |:---------:| -------:|
| Uses a custom Component | X | In a future release |
| Reduce Image Sizes | X | X |
| Optimise for various viewpoints (resize) | X | X |
| Lazy load based on page position | X |  |
| Convert to next generation image formats (WebP) | X | X |
| Progressive image loading | | X |
| Inlines small images | | X |
| Adds content hash for caching | | X |
| Optimises SVGs | | X |
| Generate placeholders for images before loading | | X |
| Optimises images from Cloud Providers | X | ~ |
| Easy to setup | Built in | NPM packages, changes to next.config.js required |

So it looks like that the Next.js Image component does the basics but if you're looking for a full image optimisation solution for Next.js, next-optimized-images still has it's place.

### Ease of use 

Example Next.js code:

```javascript
function DemoMyImage() {
  return <img src="./picture.jpg" alt="a picture" height="200" width="100" />
}
```

**Next.js Image Component**

To change the example code to use the `<Image>` component, it just needs to be imported.

```javascript
import Image from 'next/image'

function DemoMyImage() {
  return <Image src="./picture.jpg" alt="a picture" height="200" width="100" />
}
```


**Next-optimized-images (V2/current)**

*Next-optimized-images also has a V3 on the way with it's own Image component, I've written about it a little further down.*

As next-optimized-images is an external plugin, it's a little more complicated to setup.

First we need to install the package and any packages needed for image optimisation. As the example image is a JPEG, we need to add the `imagemin-mozjpeg` and `webp-loader` packages to enable JPEG optimisation and WebP conversion. We will also add the `responsive-loader` package which enable image resizing.

```bash
npm install -s next-optimized-images imagemin-mozjpeg responsive-loader sharp
```

Next we need to update the Next.js config to enable the image optimisation.

```javascript
// next.config.js
const optimizedImages = require('next-optimized-images');
module.exports = optimizedImages();
```

With image resizing, JPG optimisation and potential WebP conversion, the example using the plugin will be:

```javascript
function DemoMyImage() {
  const imgSrc = require('./picture.jpg?resize&size=100');
  return <img src={imgSrc.src} alt="a picture" />
}
```

**Next-optimized-images (V3/Canary)**

Next-optimized-images V3 is a complete re-write of the existing extension that hopes to squash all existing bugs with V2. In V3 you can import an image using `import` rather than `require` and take advantage of an `<Img>` Component like the Next.js built in <Image> one.

Setup for V3 is on the [canary branch](https://github.com/cyrilwanner/next-optimized-images/tree/canary).

Let's take a look at the usage of the `<Img>` Component.

```javascript
import Img from 'react-optimized-image';
import MyImage from './picture.jpg';

function DemoMyImage() {
  // Attempt WebP conversion and fallback to JPEG
  <Img src={MyImage} webp sizes={[100]} />
}
```

As you can see it's much cleaner than V2's require system using queries to do resizing (`?resize`). It also appears much more customisable than the Next.js `<Image>` component as it can take advantage of all the functionality that next-optimized-images has gained over the years. 

V3's release date is currently unknown and it may contain bugs so if you want to use a custom image Component, the Next.js one is the safer bet as it is fully released and supported.

**Code Comparison Summary**

Although the initial setup was expectedly longer than the built-in component, once it's done you can just add a `require()` around the existing file path.

## Conclusion

The new built-in Image Component is a great starting point when optimising your images but next-optimized-images still appears to be capable of handling more image types and providing more customisation such as progressive image loading and placeholders.

That said, in projects that use a small number of images the Next.js Image Component is likely the better fit as it works out the box and will optimise images without any further configuration. I'm sure in the future the Image Component will only get better so it'll be interesting to see what it does differently to the next-optimized-images plugin, especially since V3 contains it's own React Component.

All the new features in version 10 provide yet more reasons for Next.js to become your go-to React.js framework and I am excited to try them all - especially the Image Component.

What do you think about the new Image component? Let me know in the comments and drop a reaction!