Superior Image Optimization: An Ideal Solution Using Gatsby & ImageEngine

(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:

OptionDefaultDescription
layoutconstrained / CONSTRAINEDDetermines the size of the image and its resizing behavior.
width/heightSource image sizeChange the size of the image.
aspectRatioSource image aspect ratioForce a specific ratio between the image’s width and height.
placeholder"dominantColor" / DOMINANT_COLORChoose 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.
sizesGenerated automaticallyThe <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.
quality50The default image quality generated. This is override by any format-specific option.
outputPixelDensitiesFor fixed images: [1, 2]

For constrained: [0.25, 0.5, 1, 2]
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.
blurredOptionsNoneOptions for the low-resolution placeholder image. Ignored unless placeholder is blurred.
tracedSVGOptionsNoneOptions for traced placeholder SVGs. See potrace options. Ignored unless placeholder is traced SVG.
jpgOptionsNoneOptions 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.

Start Serving Optimized Images in Vue

Images have become extremely important to the effectiveness of websites. They speak a 1000 words, attract attention, and stimulate emotions.

However, web performance is also a growing problem for most websites. And images are at the heart of many web performance issues. According to HTTP Archive, images are at least 50% of total website payloads.

If you have ever tried to lower the size of the images, then you know how painful the process is. Poorly optimized images can end up blurry or pixelated.

Thankfully, today we have a large number of external services just for this purpose. We will talk about the ImageEngine image CDN and how to implement it using Vue.js. But first, let’s learn about CDNs and ImageEngine.

What is an Image CDN?

A content delivery network (CDN) is a global network of servers that optimizes web performance by using the node closest to the user for faster delivery of assets. An Image CDN adds real-time image optimization prior to delivering images from the CDN. An Image CDN decreases image payload, and instantly sends images from the edge of the network. The result is faster page loading that drives higher SEO ranking and better user experience.

What is ImageEngine?

ImageEngine is an image CDN with automatic, real-time image optimization. What makes ImageEngine stand out from the crowd is the way ImageEngine analyses the request to dynamically provide a visually high-quality image at the lowest possible byte size based on the device or browser’s capabilities. ImageEngine is the only image CDN utilizing mobile device detection to specifically optimize images according to the requesting device or browsers capabilities.

With ImageEngine, You don’t need to worry about URL parameters with quirky syntax or JavaScript libraries. Instead, you can just prefix the image URL with an ImageEngine Delivery Address, and the service will automatically detect the mobile device, optimize the image appropriately, and deliver the most efficient image with good quality possible.

We will show you how to use ImageEngine CDN inside our Vue.js application to deliver optimized images. What’s great is that you don’t need to re-upload images to use the service. You only need to point ImageEngine service at the existing storage location of images (or, as ImageEngine calls this an “Origin”).

Integrating ImageEngine Into Your Website for Better Web Performance

If you’d like to follow along, sign up for a free trial account before moving on. After signing up for a trial account, you’ll get access to a control panel where you can further configure ImageEngine for your website or app.

I’ve built a demo app to demonstrate how effortless the integration is at the app level. It takes only a few easy steps to get rolling.

Step 1 – Point ImageEngine at Original Images

Before we get into the code, you will need to point ImageEngine’s “Engine” at the host where the images are stored. This can be your website, Amazon S3, or Google Cloud Storage.

As you can see in the above screenshot of the Dashboard configuration. We added the origin (named “default”) with host pointing to our demo sandbox Vue application https://4fzq3.csb.app/

We don’t need to re-upload images to the CDN or anywhere else. If you take a look at the demo project’s structure, you’ll see that all the pictures sit inside the public/images folder:

ImageEngine will automatically take these pictures in the public/images folder, optimize them, and serve the optimized images from its own CDN. And with the Vue component we will show you, we don’t need to change URLs inside our code either.

Step 2 – Proxy Image Requests inside Vue application

Let’s start with Vue.js implementation. You have two implementation options. Both involve adding the Delivery Address ImageEngine provided. Your Delivery Address should end in .imgeng.in, so have it copied and ready for use.

Once you have your Delivery Address we can proceed with code implementation. Our Example Delivery Address is https://c4ltipq2.cdn.imgeng.in/

Option 1: Prefix Image Tags

To send image requests to ImageEngine, you will need to prepend the existing image src path with the new Delivery Address found in your account’s dashboard.

<img :src="imgengHostConst + '/images/pic_2.jpg'" />

We need to install the npm package @imageengine/vue and add it as a dependency.

In the terminal, write:

npm i @imageengine/vue

You have everything set, we are ready to do some coding.

You will need to import the ImageEngineProvider component from the npm package and pass the Delivery Address as the property deliveryAddress, and wrap it around your application or image components.

<ImageEngineProvider deliveryAddress="https://c4ltipq2.cdn.imgeng.in/">
  …APP…
</ImageEngineProvider>

Replace all HTML image elements with ImageComponent components.

For example:

<img src="/images/pic_2.jpg"/>

<!-- Changes to -->
<ImageComponent src="/images/pic_2.jpg" />

The image component requires only the src property to be passed in. Optionally, you can pass the srcSet and directives properties which give you more control of your image optimization. Using directives, you can set output format, width, height, compression and more.

After using the ImageEngineProvider component, your images are optimized and delivered through the ImageEngine CDN.

You can see all image directives, properties and formats that you can pass that impact compression and optimization on the npm package documentation page.

Below is a table that shows the image format conversion and image payload reduction that ImageEngine provided for our sample app

Image NameOriginal FormatFormat With ImageEngineOriginal SizeSize after ImageEnginePayload Reduction
pic_2.jpgJPEGWebP4.8 MB570 kB88%
pic_2.jpgJPEGWebP3.3 MB141 kB96%
pic_1_variation_1.jpgJPEGWebP2.8 MB72 kB97%

Step 3 (optional). Best Practices And Customization

To get the most out of ImageEngine, consider going through their list of best practices. In case you need to tweak your images (resizing, cropping, etc.), ImageEngine lets you apply manipulations via directives.

Code example using directives:

<ImageComponent
  src="images/pic_2.jpg"
  :directives="{
    outputFormat: 'webp',
    rotate: 45
  }"
/>

Using directives attributes, we specified an outputFormat of WebP and rotated the image 45 degrees. You can combine directives, use when you need, and where you need. It is fully dynamic.

In most cases, ImageEngine’s automatic default settings generate impressive results, so directives are usually not needed except for some customized requirements.

Conclusion

When you look at the effort invested vs. the web performance gains, ImageEngine is one of the few examples where the quality of service really gets what you want. You no longer need to worry about image size, format, resolution, etc… We made a separate package for Vue.js developers because we know how important it is to have good CDN support for the Vue.js framework. You can start using our service inside Vue.js applications in just a few steps.

Give your web/app visitors the best experience they deserve.


The post Start Serving Optimized Images in Vue appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.