NextJS custom image loader with WebP support and polyfill
Using next/image component with custom loader that supports both webp and jpeg polyfill in Safari. Three possible solutions and example with Contentful API.
Table of Contents
Case
I wanted to reduce Vercel's bandwidth usage by serving images directly from CMS. But there were also a few requirements:
- sticking to the original next/image implementation
- serving assets in .webp whenever it's possible with a fallback to .jpeg format
- make it as self-manageable as possible
I am using Contentful Images API here as an example, but I bet your CMS uses something similar! (Most of them use Filestack under the hood)
Problem
In next.js, there's no official way to check whether the browser supports webp format or not while using custom image loader feature. This could be fixed through a custom server, but Vercel does not support this.1
Solutions
Using Next.js redirects
If you're using a recent Next.js version (greater than v10.2.0), this might be a great solution. It adds a little overhead to each request, but it is hard to make them stack up to a degree that causes problems.
Pros:
- Serverless (and so, easy to scale)
- No need to maintain in any way
- 99.99% Uptime guaranteed
- Easy and quick to use (but coding this wasn't fun!)
- Server-side solution, so it will work with JavaScript disabled
- Works everywhere
Cons:
- Won't work on older Next.js versions (greater than v10.2.0 required)
- Extremely hacky Regex-like syntax path-to-regexp
- Increases network overhead (redirects). In my case, it adds a minor 30-60ms delay to each request
Client-side solution
This one should work in theory, but I have never tested it myself. I like keeping important libraries up-to-date, and this solution makes it a little bit harder, so I had to pass on it. You could use this script to check if your browser supports webp images, and assign its result to a global variable. Then, based on its value replace the src attribute with the appropriate format's extension2.
Keep in mind that the script needs to be blocking (takes ~1ms so don't worry) and loaded before any next.js chunk. To preserve these changes on every install you can use patch-package.
Pros:
99.99% Uptime guaranteed
No network overhead at all
No scalability issues
No maintenance's needed
Cons:
Client-side only, but it won't affect anything important (like SEO)
Patching next.js (makes it harder to update)
Might not work in sketchy browsers
Using a proxy
You could use existing products like Nginx or even code a custom one. The idea stays the same, redirect to a correct format based on Accept header. But numerous cons make this (at least) not an ideal solution.
Pros:
- Quick & easy to setup
Cons:
- Not quick & not so easy to maintain
- Not serverless
- You might encounter scalability issues in big-scale projects
- Increase in network overhead
- Images are not served directly from CMS so you would have to pay more
Footnotes
Published on July 31, 2021 • 4 min read