Introduction
Next.js Image Optimization is easy. The blog you're reading uses both the latest version of React and Next.js.
You must make sure that
1next.config.js
1module.exports = {
2 images: {
3 formats: ['image/avif', 'image/webp']
4 }
5}
Next.js will handle all the hard work behind the scenes for you. The team behind Next.js has been working to improve image processing since version 10 and AVIF is supported since version 12. They offer both an integrated
1<Image>
1next/image
See the Next.js Documentationfor more information.
Next.js image component
To use the Next.js image component, you add the image file to your project directory or use an external source and pass it as a
1src
1import Image from 'next/image'
2(..)
3 <Image
4 src="/yourmum.jpg"
5 alt="Picture of your mum"
6 width={9001}
7 height={500}
8 />
9(..)
CSS Images
Until this point, if you rely heavily on CSS images, you can use the third-party plugin with Next.js called next-optimized-images. It has many additional features, and it ** supports loading images with CSS**, which is useful. However, the plugin does not support AVIF and opts for WebP. Even though the author released news on a new version following a canary branch with promised AVIF support, the development has not been continued as of August 2020.
How do we at avif.io deal with AVIF support?
As we don't want to rely on Vercel or third-party components, we perform the following steps.
1. Add browser support detection script
To find out if you as a visitor have a browser with AVIF support, we have implemented the following 600-byte script in our header:
1function F(a){document.documentElement.classList.add(a)}var A=new Image;A.src="data:image/avif;base64,AAAAFGZ0eXBhdmlmAAAAAG1pZjEAAACgbWV0YQAAAAAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAC8AAAAGwAAACNpaW5mAAAAAAABAAAAFWluZmUCAAAAAAEAAGF2MDEAAAAARWlwcnAAAAAoaXBjbwAAABRpc3BlAAAAAAAAAAQAAAAEAAAADGF2MUOBAAAAAAAAFWlwbWEAAAAAAAAAAQABAgECAAAAI21kYXQSAAoIP8R8hAQ0BUAyDWeeUy0JG+QAACANEkA=",A.onload=function(){F("avif")},A.onerror=function(){var a=new Image;a.src="data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",a.onload=function(){F("webp")}};
2. Create image component with modern markup
We have developed our own image component (visit Github for the latest version), which uses all the features that modern image markup should take into account, from the lazy load to the aspect ratio. We have to choose a path and an alt text. For more information on the perfect image markup visit Guide to Image Performance.
3. Convert images with sharp on build time
Finally, we have the NodeJS library sharpintegrated into our build and release script to convert images before we upload our website data to Firebase. The sharp script detects all images in a specific folder and converts them into all the different formats and sizes we need. Below is the current script we are using.
1const sharp = require("sharp");
2const fs = require("fs");
3const path = require("path");
4const output = "../public/img/";
5const input = "../images/";
6const jpgQuality = { mozjpeg: true, quality: 50, progressive: true };
7const webpQuality = { quality: 50, reductionEffort: 6 };
8const avifQuality = { quality: 45, speed: 1 };
9const sizes = [1440, 720, 360];
10fs.readdir(input, (err, files) => {
11 console.log("Found " + files.length + " files. Converting now, please be patient..");
12 files.forEach((file) => {
13 function convert(size) {
14 let fileShort = path.parse(file).name;
15 sharp(input + file)
16 .jpeg(jpgQuality)
17 .resize({ width: size })
18 .toFile(output + fileShort + "-" + size + ".jpg");
19 sharp(input + file)
20 .webp(webpQuality)
21 .resize({ width: size })
22 .toFile(output + fileShort + "-" + size + ".webp");
23 sharp(input + file)
24 .avif(avifQuality)
25 .resize({ width: size })
26 .toFile(output + fileShort + "-" + size + ".avif");
27 }
28 if (file.endsWith(".png") || file.endsWith(".jpg") || file.endsWith(".jpeg")) {
29 for (let i = 0; i < sizes.length; i++) {
30 convert(sizes[i]);
31 }
32 }
33 });
34});
35
Keep in mind that this is suitable for website without many images, as it significantly increases build time. A way to bypass that could be creating an own sharp API and using Incremental Static Regeneration.