This post was originally published at codebushi.com
For a video tutorial, check out https://www.youtube.com/watch?v=kOrohVsq_kI
Gatsby.js V2 was recently launched and there have been a few small changes to how Gatsby Image is implemented. Gatsby Image is a React component that makes it easy to optimize all the images on your website. It will resize images for you, so you don't load huge images on a mobile device, and it will also lazy load your images with a cool "blur-up" effect so that your initial page loads are blazing fast. If you're new to Gatsby, I highly recommend going through their official tutorial first and familiarize yourself with how Gatsby works.
Adding Gatsby Image to your static website can be a bit tricky, especially since Gatsby uses GraphQL to query and load your images before they can be used. Here's a breakdown of the steps needed:
1) Install the required npm packages and configure your gatsby-config.js
settings.
2) Test that you can query for your images using GraphQL.
3) Choose which image type you will need, fixed or fluid, and add the query to your page.
4) Use Gatsby Image <Img>
tags on your page.
Here's a demo of the final product:
Gatsby Image Demo ( view source )
Installing & Configuring Gatsby Image
We'll start off by installing the default Gatsby Starter. You can clone the repo or use the Gatsby CLI to install the starter.
gatsby new image-demo https://github.com/gatsbyjs/gatsby-starter-default
cd image-demo/
If you used the CLI, you'll need to continue with yarn
since the initial packages were installed with yarn
and there will be a yarn.lock file. If you cloned the repo and used npm install
, then continue to use npm
so you don't mix the package installers. I'll be using yarn
for the rest of this demo.
Install Gatsby Image
yarn add gatsby-image
We'll also need three other packages, gatsby-transformer-sharp, gatsby-plugin-sharp, and gatsby-source-filesystem. If you are not using the default starter and already have these packages installed, you can skip this step.
yarn add gatsby-transformer-sharp gatsby-plugin-sharp gatsby-source-filesystem
The gatsby-source-filesystem
package allows Gatsby to use GraphQL on the images in a certain directory and make queries out of them. The two sharp
plugins are what processes the images before you display them.
Open up your gatsby-config.js
and add the plugins to it. I'll add them right before the existing plugins. Your file should look like this:
module.exports = {
siteMetadata: {
title: 'Gatsby Default Starter',
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/src/images`,
name: 'images',
},
},
'gatsby-transformer-sharp',
'gatsby-plugin-sharp',
'gatsby-plugin-react-helmet',
{
resolve: `gatsby-plugin-manifest`,
options: {
name: 'gatsby-starter-default',
short_name: 'starter',
start_url: '/',
background_color: '#663399',
theme_color: '#663399',
display: 'minimal-ui',
icon: 'src/images/gatsby-icon.png', // This path is relative to the root of the site.
},
},
'gatsby-plugin-offline',
],
}
Important: Make sure you specify the correct path
to your images! The gatsby-source-filesystem
will look in this folder to access your images. Since we're using the default starter, there's already a folder at /src/images
so we'll use that. Get some images off of Unsplash and add them to that folder.
Testing An Image Query With GraphQL
With the plugins installed, we can fire up our site in dev mode.
gatsby develop
Navigate to http://localhost:8000/
to see your site in dev mode. Now we'll play with the GraphiQL interface to understand how the image query works. Head to http://localhost:8000/___graphql
to see the GraphiQL view of the site. Here we can test the different queries available to us. I've added 3 images to my /src/images
folder and named them one.jpg
two.jpg
and three.jpg
. To query for one.jpg
I'll use this:
query {
imageOne: file(relativePath: {eq: "one.jpg"}) {
childImageSharp {
fluid(maxWidth: 1000) {
base64
tracedSVG
aspectRatio
src
srcSet
srcWebp
srcSetWebp
sizes
originalImg
originalName
}
}
}
}
If you hit the play button, you should see data in the response column. This proves that Gatsby is able to find your image and process it.
Try changing file(relativePath: {eq: "one.jpg"})
to the other images in that folder, and make sure you see the data return.
Adding The GraphQL Query
We can now copy this query and use it in our homepage component. Open up src/pages/index.js
. You'll need to import graphql
from 'gatsby'
as well as Img
from 'gatsby-image'
. We'll add the query to the page, the final result looks like this:
import React from 'react'
import { Link, graphql } from 'gatsby'
import Img from 'gatsby-image'
import Layout from '../components/layout'
const IndexPage = (props) => (
<Layout>
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
export default IndexPage
export const pageQuery = graphql`
query {
imageOne: file(relativePath: { eq: "one.jpg" }) {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
`
The query looks a bit different than before, we've removed all the fields inside fluid(maxWidth: 1000) {}
and used ...GatsbyImageSharpFluid
, which is a "query fragment". Due to some limitations, we were not able to play with ...GatsbyImageSharpFluid
before in GraphiQL, but we can add it here. You can read more about the different fragments on the Gatsby Image Readme.
Important: Notice how the file(relativePath: { eq: "one.jpg" })
part remains the same, this is because the relativePath
is not relative to index.js
but rather the folder you specified earlier in gatsby-config.js
and the gatsby-source-filesystem
. There is no need to change anything about the relativePath
.
Gatsby Image has two types of responsive images, fixed
and fluid
. This distinction will vary what your query looks like. A fixed
query has a set width and height and is for supporting different screen resolutions. A fluid
query has a max-width and sometimes a max-height, and will create multiple images for supporting different screen sizes. For the most part, I find myself using the fluid
type since my images will vary depending on the size of the screen. If you want to use the fixed
type or wish to learn more about the two, check out the Readme.
Using The Gatsby Image Component
So we have our query on the page, the GraphQL data can be accessed via props
in our IndexPage
component. The full path to the data is props.data.imageOne.childImageSharp.fluid
. We can pass this into the <Img>
component like so:
<Img fluid={props.data.imageOne.childImageSharp.fluid} />
You can destructure this however you like, I'm using the full path for clarity. The image should now be displaying on your dev site! To get all three images, just copy and paste the imageOne
blocks and rename to imageTwo
and imageThree
. You can call these whatever you want, just make sure it matches whatever you pass into the <Img />
component.
query {
imageOne: file(relativePath: { eq: "one.jpg" }) {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
imageTwo: file(relativePath: { eq: "two.jpg" }) {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
imageThree: file(relativePath: { eq: "three.jpg" }) {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
The components would look like this:
<Img fluid={props.data.imageOne.childImageSharp.fluid} />
<Img fluid={props.data.imageTwo.childImageSharp.fluid} />
<Img fluid={props.data.imageThree.childImageSharp.fluid} />
We're repeating a lot of the same stuff inside that query, it can be cleaned up by making a custom fragment. Pull out the childImageSharp
blocks and make a new fragment like so:
export const fluidImage = graphql`
fragment fluidImage on File {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
`;
We can then replace the repeating code with this new fragment like so:
export const pageQuery = graphql`
query {
imageOne: file(relativePath: { eq: "one.jpg" }) {
...fluidImage
}
imageTwo: file(relativePath: { eq: "two.jpg" }) {
...fluidImage
}
imageThree: file(relativePath: { eq: "three.jpg" }) {
...fluidImage
}
}
`
We'll now have all three images on our homepage! You can play around with the different Gatsby fragments for different loading effects. ...GatsbyImageSharpFluid
will give the "blur up" effect, try ...GatsbyImageSharpFluid_tracedSVG
for a different effect and experiment with fixed images.
Top comments (4)
Excellent tutorial Hunter! Quick question, if you don't mind. Why does the
pageQuery
const need to be exported? Is this simply howGatsby-image
accesses the query? Thanks!Yes, that's how the component is able to consume the GraphQL query. I think it needs to be exported because that's how Gatsby is able to process it during the build. Check out this page for more info: gatsbyjs.org/docs/page-query
Hallo, thank you so much for this helpful guide! The DRY code at the end was a gem. If you don't mind asking me though, would you happen to know how to test a component that uses gatsby-image?
This is a good learning curve to get going with graphql and gatsby-image. Nicely structured.