Make your designer happier with Gatsby’s image manipulations

Aggelos Arvanitakis
ITNEXT
Published in
6 min readSep 17, 2019

--

Do you have a designer in your team? Well, I do and he’s a grumpy one, let’s call him Jim. People normally go to Jim for all sorts of things; to let him know that they preferred the design they saw in another website, to complain about a particular interface he implemented or to simply ask him to resize an image in certain dimensions. Designers get all sorts of weird requests and all that Jim wants deep down inside, is what most developers also crave for; to be left alone to do his job.

Luckily for Jim, Gatsby ships with some incredibly powerful plugins for image manipulation, performing operations that would normally require a designer (or an external 3rd-party software) to perform. This article will focus on just that, making sure that next time you create a static website, you definitely consider Gatsby as an option.

Before we begin, it’s good to give a little background on how things work on Gatsby.

Gatsby is part of the so-called “JAM” stack, where Javascript libraries utilise particular APIs in order to produce static Markup in HTML. Gatsby’s API is GraphQL which allows you to query for data as if they were in a database. These data are modeled as “nodes” which you can think of as “entities” in a database world. The question is, how does Gatsby create the data (nodes) in the first place?

The answer lies in plugins, which is the main way you are allowed to interact with Gatsby’s underlying infrastructure. There are two types of plugins:

  • Source Plugins: Responsible for creating new top-level nodes (data). For example, you can add the gatsby-source-filesystem plugin and every file in your project will become a node that you can query for using GraphQL. This allows you to fetch all the files of a certain directory, fetch the contents of a particular file, etc.
  • Transformer Plugins: Responsible for taking existing nodes and transforming them into other types of nodes, maintaining a parent-child relationship with the node they were transformed from. An example of that would be the gatsby-transformer-json plugin, which takes the nodes created by gatsby-source-filesystem and parses the raw content into JSONmakes sure that you can instantly query the content of all JSON-file nodes.

By utilising transformer plugins we can take an image node (a.k.a. an image file) and transform into another image node. With this in mind, we can convert a JPG image node to a PNG image node; all we need is the proper plugin. Thankfully, Gatsby provides three (3) separate plugins for that: gatsby-plugin-sharp, gatsby-transformer-sharp and gatsby-image.

gatsby-plugin-sharp is a link between Gatsby and Sharp, one of the fastest Node.js image processing libraries out there. As a library, Sharp allows you to transform, resize, enhance and re-format images through its functional API, but in order to use it within Gatsby, we need a bridging API that will translate Gatsby stuff to Sharp stuff. I know it doesn’t make much sense, but bear with me, it will in just a bit.

gatsby-transformer-sharp is a transformer plugin that transforms typical image-file nodes — which have been created by a source plugin (with data from your local filesystem, wordpress, contentful, etc.) — to ImageSharp nodes. What’s the difference between a ImageSharp node and just a typical image-file node? Well, ImageSharp nodes have access to the Shrap API that our previous bridging plugin has created. This API is exposed as a set of GraphQL query parameters which configure the transformation process that Sharp performs.Thus, you can transform & process the image right-there when you ask for it. Sounds complicated? Let’s simplify it a bit.

  1. You query for your image using GraphQL.
  2. You specify a set of query parameters on your GraphQL query.
  3. Based on the values you’ve specified, you get back a processed (transformed) image instead of the original one.

Ok so big whoop, being able to resize & transform an image with GraphQL is cute, but it’s not the most useful thing in the world, right? Well, hold your horses because apart from modifying the existing images, you can also generate a new set of images that will be used on different screen widths & resolutions. Instead of manually creating different variations of an image to use on different device viewports, Gatsby can create these variations for you automatically. Think about that for a second; think about all the times you had to create multiple resolutions for an image by going to Photoshop, Sketch or MS Paint and tweaking the dimensions & resolutions manually in order to save some precious KB. With Gatsby, this is now automated. By using this plugin, you can create two (2) types of image sets: fixed and fluid.

Fluid images are images that have different sizes depending on the screen width. A fluid example would be the following:

query {     
file(relativePath: { eq: "path/to/my/image.png" }) {
childImageSharp {
# Specify the image processing specifications in the query.
fluid(maxWidth: 500, quality: 75, toFormat: "JPG") {
src
}
}
}
}

The above would load the image image.png from the local filesystem, transform it to an ImageSharp node and return the source paths (URIs) of five (5) JPG images with widths of [125, 250, 500, 750, 1000] and their resolutions reduced to 75%.

Fixed images are images that always have the same size, but their resolution changes depending on the quality of the screen they are viewed from (i.e. full-HD vs 4K). An example of that would look like this:

query {     
file(relativePath: { eq: "path/to/my/image.jpg" }) {
childImageSharp {
# Specify the image processing specifications in the query.
fixed(width: 125, height: 125) {
src
}
}
}
}

The above would load the image image.jpg from the local filesystem, transform it to an ImageSharp node and return the source paths of three (3) 125x125 images with different resolutions (1x, 1.5x and 2x).

Bear in mind that src is only one of the fields that you can query for. There are other stuff like a srcSet to use with a <picture /> element, a base64 placeholder to render while your image is being fetched, etc. For a full list, you can visit the plugin’s documentation page.

So you’ve successfully transformed your image to what you need and you have gotten back the source paths of a list of images. Now, you would expect that you have to create <picture /> elements, put a list of <img /> tags in there, add dimensions, configure breakpoints and so on and so on. Well, luckily enough, there is a neat little library called gatsby-image which exposes a React component named <Img />. This component takes the output of the aforementioned GraphQL query and sets up everything for you. Specifically, you pass in a single prop named either fluid or fixed — depending on what image you’ve created — whose value is the result of the corresponding GraphQL query. That’s it! You don’t need to do anything else in order to display your optimized image to the user. An example of how it’s used would be the following:

import React from "react"
import { graphql } from "gatsby"
import Img from "gatsby-image"

export default ({ data }) => (
<Img fixed={data.file.childImageSharp.fixed} />
)
// The results of the query whose exported name is `query` will
// automatically be added as props to the default exported
// React Component. That's a Gatsby feature...
export const query = graphql`
query {
file(relativePath: { eq: "blog/avatars/aggelos.jpeg" }) {
childImageSharp {
fixed(width: 125, height: 125) {
src
srcSet
base64
}
}
}
}
`

With <Img />, consuming those Sharp transformations now becomes a breeze, since you don’t even have to worry about the results of the GraphQL query; you just forward them to the React Component and it will handle consumption & rendering for you. Of course, you can also pass additional props to control the display and positioning of the image. For a full list of the available props, you can check out the related docs page.

Wrapping up

Image manipulation has long been one of these things that developers can’t easily tackle on their own. Almost all of us rely on external sources (be it people or software) to get what we need, which can be really frustrating and time consuming when happening often. When I heard about Gatsby, I thought it was just a quick & easy way to create a static page using React, but its plugins — and especially the image ones — take it to a whole different level. We live in an era where images dominate most websites’ content and Gatsby gives you the power to not have to think about the performance implications of your images, not have to ping Jim for an image resize and at the end of the day, help you focus on what’s really important; the content.

Thanks for reading :)

P.S. 👋 Hi, I’m Aggelos! If you liked this, consider following me on twitter and sharing the story with your developer friends 😀

--

--