(This is a sponsored post.)
In recent years, the Jamstack methodology for building websites has become increasingly popular. Performance, scalable, and secure, it’s easy to see why it’s becoming an attractive way to build websites for developers.
GatsbyJS is a static site generator platform. It’s powered by React, a front-end JavaScript library, for building user interfaces. And uses GraphQL, an open-source data query and manipulation language, to pull structured data from other sources, typically a headless CMS like Contentful.
While GatsbyJS and similar platforms have revolutionized much about the web development process, one stubborn challenge remains: image optimization. Even using a modern front-end development framework like GatsbyJS, it tends to be a time-intensive and frustrating exercise.
For most modern websites, it doesn’t help much if you run on a performant technology but your images aren’t optimized. Today, images are the largest contributor to page weight, and growing, and have been singled out by Google as presenting the most significant opportunity for improving performance.
With that in mind, I want to discuss how using an image CDN as part of your technology stack can bring improvements both in terms of website performance and the entire development process.
A Quick Introduction to Gatsby
GatsbyJS is so much more than the conventional static site generators of old. Yes, you still have the ability to integrate with a software version control platform, like Git, as well as to build, deploy, and preview Gatsby projects. However, its services consist of a unified cloud platform that includes high-speed, scalable, and secure hosting as well as expert technical support and powerful third-party integrations.
What’s more, all of it comes wrapped in a user-friendly development platform that shares many similarities with the most popular CMSs of the day. For example, you can leverage pre-designed site templates or pre-configured functions (effectively website elements and modules) to speed up the production process.
It also offers many benefits for developers by allowing you to work with leading frameworks and languages, like JavaScript, React, WebPack, and GraphQL as well as baked-in capabilities to deal with performance, development iterations, etc.
For example, Gatsby does a lot to optimize your performance without any intervention. It comes with built-in code-splitting, prefetching resources, and lazy-loading. Static sites are generally known for being inherently performant, but Gatsby kicks it up a notch.
Does Gatsby Provide Built-in Image Optimization?
Gatsby does, in fact, offer built-in image optimization capabilities.
In fact, it recently upgraded in this regard, replacing the now deprecated gatsby-image package with the brand-new Gatsby image plugin. This plugin consists of two components for static and dynamic images, respectively. Typically, you would use the dynamic component if you’re handling images from a CMS, like Contentful.
Installing this plugin allows you to programmatically pass commands to the underlying framework in the form of properties, shown below:
Option | Default | Description |
---|---|---|
layout |
constrained / CONSTRAINED |
Determines the size of the image and its resizing behavior. |
width /height |
Source image size | Change the size of the image. |
aspectRatio |
Source image aspect ratio | Force a specific ratio between the image’s width and height. |
placeholder |
"dominantColor" / DOMINANT_COLOR |
Choose the style of temporary image shown while the full image loads. |
formats |
["auto", "webp"] / [AUTO,WEBP] |
File formats of the images generated. |
transformOptions |
[fit: "cover", cropFocus: "attention"] |
Options to pass to sharp to control cropping and other image manipulations. |
sizes |
Generated automatically | The <img> sizes attribute, passed to the img tag. This describes the display size of the image, and does not affect generated images. You are only likely to change this if you are using full width images that do not span the full width of the screen. |
quality |
50 |
The default image quality generated. This is override by any format-specific option. |
outputPixelDensities |
For fixed images: [1, 2]
For constrained: |
A list of image pixel densities to generate. It will never generate images larger than the source, and will always include a 1✕ image. The image is multiple by the image width, to give the generated sizes. For example, a 400px wide constrained image would generate 100 , 200 , 400 and 800px wide images by default. Ignored for full width layout images, which use breakpoints instead. |
breakpoints |
[750, 1000, 1366, 1920] |
Output widths to generate for full width images. Default is to generate widths for common device resolutions. It will never generate an image larger than the source image. The browser will automatically choose the most appropriate. |
blurredOptions |
None | Options for the low-resolution placeholder image. Ignored unless placeholder is blurred. |
tracedSVGOptions |
None | Options for traced placeholder SVGs. See potrace options. Ignored unless placeholder is traced SVG. |
jpgOptions |
None | Options to pass to sharp when generating JPG images. |
As you can see, that’s quite the toolkit to help developers process images in a variety of ways. The various options can be used to transform, style, and optimize images for performance as well as make images behave dynamically in a number of ways.
In terms of performance optimization, there are a few options that are particularly interesting:
- Lazy-loading: Defers loading of off-screen images until they are scrolled into view.
- Width/height: Resize image dimensions according to how they will be used.
- Placeholder: When lazy-loading or while an image is loading in the background, use a placeholder. This can help to avoid performance penalties for core web vitals, like Cumulative Layout Shift (CLS).
- Format: Different formats have inherently more efficient encoding. GatsbyJS supports WebP and AVIF, two of the most performant next-gen image formats.
- Quality: Apply a specified level of quality compression to the image between 0 and 100.
- Pixel density: A lower pixel density will save image data and can be optimized according to the screen size and PPI (pixels per inch).
- Breakpoints: Breakpoints are important for ensuring that you serve a version of an image that’s sized appropriately for a certain threshold of screen sizes, especially that you serve smaller images for smaller screen sizes, like tablets or mobile phones. This is called responsive syntax.
So, all in all, Gatsby provides developers with a mature and sophisticated framework to process and optimize image content. The only important missing feature that’s missing is some type of built-in support for client hints.
However, there is one big catch: All of this has to be implemented manually. While GatsbyJS does use default settings for some image properties, it doesn’t offer built-in intelligence to automatically and dynamically process and serve optimized images tailored to the accessing device.
If you want to create an ideal image optimization solution, your developers will firstly have to implement device detection capabilities. They will then need to develop the logic to dynamically select optimization operations based on the specific device accessing your web app.
Finally, this code will continually need to be changed and updated. New devices come out all the time with differing properties. What’s more, standards regarding performance as well as image optimization are continually evolving. Even significant changes, additions, or updates to your own image assets may trigger the need to rework your implementation. Not to mention the time it takes to simply stay abreast of the latest information and trends and to make sure development is carried out accordingly.
Another problem is that you will need to continually test and refine your implementation. Without the help of an intelligent optimization engine, you will need to “feel out” how your settings will affect the visual quality of your images and continually fine-tune your approach to get the right results.
This will add a considerable amount of overhead to your development workload in the immediate and long term.
Gatsby also admits that these techniques are quite CPU intensive. In that case, you might want to preoptimize images. However, this also needs to be manually implemented in-code on top of being even less dynamic and flexible.
But, what if there was a better way to optimize your image assets while still enjoying all the benefits of using a platform like Gatsby? The solution I’m about to propose will help solve a number of key issues that arise from using Gatsby (and any development framework, for that matter) for the majority of your image optimization:
- Reduce the impact optimizing images have on the development and design process in the immediate and long term.
- Remove an additional burden and responsibility from your developers’ shoulders, freeing up time and resources to work on the primary aspects of your web app.
- Improve your web app’s ability to dynamically and intelligently optimize image assets for each unique visitor.
- All of this, while still integrating seamlessly with GatsbyJS as well as your CMS (in most cases).
Introducing a Better Way to Optimize Image Assets: ImageEngine
In short, ImageEngine is an intelligent, device-aware image CDN.
ImageEngine works just like any other CDN (content delivery network), such as Fastly, Akamai, or Cloudflare. However, it specializes in optimizing and serving image content specifically.
Like its counterparts, you provide ImageEngine with the location where your image files are stored, it pulls them to its own image optimization servers, and then generates and serves optimized variants of images to your site visitors.
In doing this, ImageEngine is designed to decrease image payload, deliver optimized images tailored to each unique device, and serve images from edge nodes across its global CDN.
Basically, image CDNs gather information on the accessing device by analyzing the ACCEPT
header. A typical ACCEPT
header looks like this (for Chrome):
image/avif,image/webp,image/apng,image/*,*/*;q=0.8
As you can see, this only provides the CDN with the accepted image formats and the recommended quality compression.
More advanced CDNs, ImageEngine, included, can also leverage client hints for more in-depth data points, such as the DPR (device pixel ratio) and Viewport-Width. This allows a larger degree of intelligent decision-making to more effectively optimize image assets while preserving visual quality.
However, ImageEngine takes things another step further by being the only mainstream image CDN that has built-in WURFL device detection. This gives ImageEngine the ability to read more information on the device, such as the operating system, resolution, and PPI (pixels per inch).
Using AI and machine-learning algorithms, this extra data means ImageEngine has virtually unparalleled decision-making power. Without any manual intervention, ImageEngine can perform all of the following image optimization operations automatically:
- Resize your images according to the device screen size without the need for responsive syntax.
- Intelligently compress the quality of the image to reduce the payload while preserving visual quality, using metrics like the Structural Similarity Index Method (SSIM).
- Convert images to the most optimal, next-gen encoding formats. On top of WebP and AVIF, ImagEngine also supports JPEG 2000 (Safari), JPEG XR (Internet Explorer & Edge), and MP4 (for aGIFs).
These settings also play well with GatsbyJS’ built-in capabilities. So, you can natively implement breakpoints, lazy-loading, and image placeholders that don’t require any expertise or intelligent decision-making using Gatsby. Then, you can let ImageEngine handle the more advanced and intelligence-driven operations, like quality compression, image formatting, and resizing.
The best part is that ImageEngine does all of this automatically, making it a completely hands-off image optimization solution. ImageEngine will automatically adjust its approach with time as the digital image landscape and standards change, freeing you from this concern.
In fact, ImageEngine recommends using default settings for getting the best results in most situations.
What’s more, this logic is built into the ImageEngine edge servers. Firstly, with over 20 global PoPs, it means that the images are processed and served as close to the end-user as possible. It also means that the majority of processing happens server-side. With the exception of installing the ImageEngine Gatsby plugin, there is virtually no processing overhead at build or runtime.
This type of dynamic, intelligent decision-making will only become more important in the near and medium-term. Thanks to the number and variety of devices growing by the year, it’s becoming harder and harder to implement image optimization in a way that’s sensitive to every device.
That’s why ImageEngine can give you the edge in a mobile-first future that’s continually evolving. Simply put, ImageEngine will help futureproof your Gatsby web app.
How to Integrate ImageEngine with Gatsby: A Quick Guide
Integrating ImageEngine with GatsbyJS is trivial if you have experience installing any other third-party plugins. However, the steps will differ somewhat based on which backend CMS you use with GatsbyJS and where you store your image assets.
For example, you could use it alongside WordPress, Drupal, Contentful, and a range of other popular CMSs.
Usually, your stack would look something like this:
- A CMS, like Contentful, to host your “space” where you’ll manage your assets and create structured data. Your images will be uploaded and stored in your space.
- A versioning platform, like Github, to host your code and manage your versions and branches.
- GatsbyJS to host your workspace, where you’ll build, deploy, and host the front end of your website.
So, the first thing you need to do is set up a site, or project, using GatsbyJS and link it to your CMS.
Next, you’ll install the ImageEngine plugin for GatsbyJS:
npm install @imageengine/gatsby-plugin-imageengine
You’ll also need to create a delivery address for your images via ImageEngine. You can get one by signing up for the 30-day trial here. The only thing you need to do is supply ImageEngine with the host origin URL. For Contentful, it’s images.ctfassets.net
and for Sanity.io, it’s cdn.sanity.io
.
ImageEngine will then provide you with a delivery address, usually in the format of {random_string}.cdn.imgeng.in
.
You’ll use this delivery address to configure the ImageEngine plugin in your gatsby-config.js
file. As part of this, you’ll indicate the source (Contentful, e.g.) as well as provide the ImageEngine delivery address. You can find examples of how that’s done in the documentation here.
Note that the ImageEngine plugin features built-in support for Contentful and Sanity.io as asset sources. You can also configure the plugin to pull locally stored images or from another custom source.
Once that’s done, development can begin!
Basically, Gatsby will create Graphql Nodes for the elements created in your CMS (e.g., ContentfulAsset
, allSanityImageAsset
, etc.). ImageEngine will then create a child node of childImageEngineAsset
for each applicable element node.
You’ll then use GraphQL queries in the code for your Gatsby pages to specify the properties of the image variants you want to serve. For example, you can display an image that’s 500 ✕ 300px in the WebP format using the following query:
gatsbyImageData(width: 500, height: 300, format: jpg)
Once again, you should refer to the documentation for a more thorough treatment. You can find guides for integrating ImageEngine with Contentful, Sanity.io, and any other Gatsby project.
For a competent Gatsby user, integrating ImageEngine will only take a few minutes. And, ongoing maintenance will be minimal. If you know how to use GraphQL, then the familiar syntax to send directives and create specific image variants will be nearly effortless and should take about the same time as manually optimizing images using standard Gatsby React.
Conclusion
For most web projects, ImageEngine can reduce image payloads by up to 80%. That number can go up if you have especially high-res images.
However, you can really get the most out of your image optimization by combining the best parts of a static front-end development framework like Gatsby and an image CDN like ImageEngine. Specifically, you can use both to target Google’s core web vitals:
- ImageEngine’s dynamic, intelligent, run-time optimization will optimize payloads to improve LCP, SI, FCP, and other data size-related metrics.
- Using Gatsby, you can optimize for CLS and FID using best practices and by natively implementing lazy loading and image placeholders.
ImageEngine provides an Image Speed Test tool where you can quickly evaluate your current performance and see the impact of ImageEngine on key metrics. Even for a simple GatsbyJS project, the results in the Demo tool can be impressive. If you extrapolate those percentages for a larger, image-heavy site, combining Gatsby with ImageEngine could have a dramatic impact on the performance and user experience of your web app. What’s more, your developers will thank you for sparing them from the challenging and time-consuming chore of manual image optimization.
Superior Image Optimization: An Ideal Solution Using Gatsby & ImageEngine originally published on CSS-Tricks. You should get the newsletter.