In Chapter 9, we added a hero image to the index page. If you got the image from Unsplash, as recommended, you might notice that the image file is very large. This could result in slow loading times for some users of the site.
Gatsby has plugins that work with an image processing library called Sharp (https://sharp.pixelplumbing.com/) to resize and crop images in various ways at build time. This can be combined with the gatsby-image plugin to create a powerful image processing pipeline.
Blur-up: Creates an extremely small size of the image that will load very quickly and sets that as the image, blurred, while the full image loads
Traced placeholder: Creates an SVG showing the outline of the full image that is displayed while the full image loads
In this chapter, we’ll use these plugins to optimize the hero image on the index page.
Plugins
gatsby-plugin-sharp : Low-level plugin that provides integration with the Sharp library.
gatsby-transformer-sharp : Utilizes gatsby-plugin-sharp to add additional image data to the GraphQL schema that can be used by the gatsby-background-image plugin to display optimized or processed images.
gatsby-remark-relative-images : Used to convert image paths to relative paths so that they can be matched by gatsby-remark-images. This is a plugin for gatsby-transformer-remark.
gatsby-remark-images : Exposes images in Markdown front matter so that they can be processed by Sharp. This is also a plugin for gatsby-transformer-remark.
gatsby-background-image : Provides a BackgroundImage component that is used for creating a container element with a background image that utilizes the data from gatsby-transformer-sharp. This is not a plugin but just a component that we will import into our page.
Adding the plugins to the Gatsby configuration
Updating the configuration file
First, we’ve added a new instance of the gatsby-source-filesystem plugin, to source the image data. This must be the first gatsby-source-filesystem instance in your configuration file. Sourcing the image files before the other content is necessary for the GraphQL schema to be correct. Otherwise, you may get an error when querying the image nodes.
Then, we added the two plugins to gatsby-transformer-remark . Previously, the plugin entry for this plugin was a simple string. We have changed it to be an object with a resolve and options property so that we can specify plugins for it. gatsby-remark-relative-images must come before gatsby-remark-images.
Lastly, we add the two other plugins at the end.
Updating gatsby-node.js
How gatsby-transformer-sharp works
There are a few different ways you can process images with Sharp for a Gatsby site.
Fixed images are generated at a specific width and height. A few images are generated for different pixel densities.
Fluid images are generated at different sizes for different screen sizes, and the appropriate image will be requested based on the container width.
You can also resize an image, specifying how it should be cropped.
The GraphQL query from the index page
Once we have added the transformer plugin, the heroImage field is no longer just a string. Instead, it is a node with many other fields attached to it, representing data about the image. It has fields for each representation of the image: fixed, fluid, and so on.
These fields are passed along to the BackgroundImage component that is given to us by the gatsby-background-image package. It has corresponding props such as fixed and fluid.
Each of the image fields in the GraphQL schema include many subfields which are expected to be passed into the BackgroundImage component. Instead of querying for each of these manually, the plugin defines several GraphQL fragments that we can add to our query instead.
GraphQL fragments
The query for the menu page
The menu query using a fragment
Now, anywhere we query a MarkdownRemark node, we can reference the MenuFields fragment to query for all those fields.
GatsbyImageSharpFixed
GatsbyImageSharpFluid
These fragments can then be passed to the corresponding props on the BackgroundImage component to use the image data.
Using the BackgroundImage component
Now that we’ve installed and configured the proper plugins, let’s update the index page to use the BackgroundImage component. We’ll need to adjust the GraphQL query to include the image data, then change from using a plain div to the BackgroundImage component .
Updating the index page
Previously, the GraphQL query was selecting the heroImage field from the front matter as a string and using that as the background image URL. Now that we have the gatsby-transformer-sharp plugin installed, heroImage is a node containing other fields with the image data. We select the childImageSharp field, then its fluid field, then finally we select the GatsbyImageSharpFluid fragment .
The BackgroundImage component has a fluid prop that expects the data from the GatsbyImageSharpFluid fragment. Similarly, it has a fixed prop that expects the data from the GatsbyImageSharpFixed fragment. Here, we want a fluid image, so we’re using the fluid prop.
Disabling the “blur-up” effect
If you would rather not use the “blur-up” effect with an image, it’s easy to disable it. In your GraphQL query, instead of selecting the GatsbyImageSharpFluid fragment, you can select the GatsbyImageSharpFluid_noBase64. The low-resolution image used for the blur is specified as a Base64 string. This fragment disables the effect.
Fixing the header background
Our site has another very large image that it loads. The background of the header area shows a faded image of coffee beans. This is currently not optimized. The image being loaded has a size of 5.4 MB, at a large size of 6,000 pixels by 4,000 pixels. This will definitely have an effect on page performance.
We can utilize the BackgroundImage component and the Sharp image processing to improve this as well, in a few short steps.
Moving the image
Currently, the coffee beans image is located in the root of the static directory. Here, it won’t be seen by gatsby-source-filesystem. We configured gatsby-source-filesystem to look for files in the static/img directory. So, as a first step, go ahead and move static/coffee.jpg to static/img/coffee.jpg.
Once we move the file here, and restart the server, it will be picked up and added to the GraphQL schema.
Modifying the Layout component to use a static query
The next step is to modify the Layout component. Currently, it’s setting the background image of the header via CSS. We’ll have to make a GraphQL query for the background image, then pass the data to a BackgroundImage component.
Updating the Layout component to use a static query
In the GraphQL query, we are using the file field to select a specific file – the header background image. The fluid image data is passed to the BackgroundImage component as before and replaces the header element we had previously.
The updated CSS module for the Layout component
Finally, restart the development server and go to the index page. The coffee beans image should appear in the header as before, but if you check the developer tools, the size of the image is much smaller this time – likely well under 1 MB.
The gatsby-image package
We have used the gatsby-background-image package, which gives us the BackgroundImage component for setting a background image on an element. But what about regular images defined with an img tag?
For that, we can use the gatsby-image package. Similar to gatsby-background-image , it provides an Img component that has fixed and fluid properties to accept data from the corresponding GraphQL fragment. This is meant to replace an img tag with the dynamic image data.
It provides the same benefits as the BackgroundImage component, including properly sized images and the “blur-up” effect when loading the image.
Summary
Installed various Gatsby image processing plugins
Used the BackgroundImage component from the gatsby-background-image package to use dynamic image data to improve image loading and page load time on the index page’s hero image and the layout’s header image
Briefly discussed the gatsby-image package