Rewriting A Static Website Using Gatsby and GraphQL - Part 3
Tags: gatsby, graphql, jsx, javascript
Published: 2019-03-05 14:02:31

---
title: Rewriting A Static Website Using Gatsby and GraphQL - Part 3
published: true
description: This post is all about Gatsby image! I decided to update my personal site away from Jekyll. In the process I learned about GatsbyJS, GraphQL and all of the errors! Check out this series for a granular walkthrough.
tags: gatsbyjs, graphql, JSX, javascript
canonical_url: https://tenmilesquare.com/rewriting-a-static-website-using-gatsby-and-graphql-part-3/
series: Rewriting A Static Website Using Gatsby and GraphQL
---
<b>Originally posted on <a rel="noreferrer noopener" aria-label="ten mile square site (opens in a new tab)" href="https://tenmilesquare.com/blog/" target="_blank">Ten Mile Square's blog.</a></b>

<!-- wp:paragraph -->
<p>If you’ve been following this series of posts as I rebuild my personal <a href="http://laurieontech.com">site</a> using <a href="http://gatsbyjs.com">GatsbyJS</a> and <a href="http://graphql.com">GraphQL</a>, continue on. If not, I recommend reading back on parts <a href="https://tenmilesquare.com/rewriting-a-static-website-using-gatsby-and-graphql/">one</a> and <a href="https://tenmilesquare.com/rewriting-a-static-website-using-gatsby-and-graphql-part-2/">two</a>. At this point I have migrated all of my data from static Yaml files, queried the data using GraphQL and rendered the pages using Gatsby and JXS. I've removed all references to the Liquid templating language I was using in my Jekyll code and the site is in working condition. Now I will turn my attention to images. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3> Image Processing </h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>My site actually uses a lot of images in what is an otherwise clean design. I have an image included in most of the headers I use, I have an image in my bio and I include images from each of my speaking engagements. So where to start?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let's begin with the picture for my bio. It's a one-off image in the body of my landing page and looks like this. </p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":3546,"align":"center","width":241,"height":191} -->
<div class="wp-block-image"><figure class="aligncenter is-resized"><img src="https://tenmilesquare.com/wp-content/uploads/2019/02/Screen-Shot-2019-02-15-at-3.20.35-PM-1024x817.png" alt="" class="wp-image-3546" width="241" height="191"/></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>There is a straightforward way to handle this image. I can import the image file and reference it directly in my JSX code for the home page. Something like this:</p>
<!-- /wp:paragraph -->


```jsx
import headshot from '../assets/headers/headshot.jpg'

<img className="headshot" src={headshot}/>
```

<!-- wp:paragraph -->
<p>The headshot class handles the nice circular display of the image as well as its center alignment on the page. It looks great! However, it isn't optimized. Since optimization is one of the major benefits of using Gatsby let's look at how to do that. In the process, I'll tackle a slightly more complicated use case. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 id="mce_3">Gatsby-Image</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Image optimization in Gatsby is provided by a plugin called <span class="code" style="background-color:white">`gatsby-image`</span> which is incredibly performant. In order to make use of it I'll start by using npm to install that plugin and its associated dependencies. </p>
<!-- /wp:paragraph -->

```shell
npm install gatsby-image gatsby-transformer-sharp gatsby-plugin-sharp
```

<!-- wp:paragraph -->
<p>Once that's done, I want to add the newly installed plugins to my gatsby-config.js file. Our config file ends up looking like this (other plugins we're already using have been removed from this snippet for simplicity). Note that once <span class="code" style="background-color:white">`gatsby-image`</span> has been installed it does not need to be included in the gatsby-config.js file.</p>
<!-- /wp:paragraph -->

```js
plugins:[
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`
]
```

<!-- wp:heading {"level":3} -->
<h3 id="mce_46">Images in Yaml</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now we're set up to tackle the more complicated use case, my speaking page. In my Jekyll site implementation each of my speaking engagements had an associated image, like this.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":3552,"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://tenmilesquare.com/wp-content/uploads/2019/02/Screen-Shot-2019-02-15-at-3.50.22-PM-1024x436.png" alt="" class="wp-image-3552"/></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>The image files were all stored in the folder labeled speaking. The yaml file that defined the data for my speaking page had references to the file name of each image. That way, when I looped through each speaking engagement, the file name would be prepended with the path to the speaking folder and the page would render the image. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>So how do I do this in Gatsby? I'm going to use GraphQL to query the image. Right now, the image file names are referenced along with the data for each speaking engagement. As a result, getting this to work requires querying the image correctly and making sure the referenced data is properly coupled with a path so the file itself can be found and processed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>I'm actually going to start by addressing the second issue first. To be honest, figuring this out was a weirdly finicky process. It turns out to be a combination of a bunch of different things but I'll try to walk through it with the solution I landed on.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Remember from the very first blogpost on this topic that the scope of what Gatsby can see is defined by the <span class="code" style="background-color:white">`gatsby-source-filesystem`</span> plugin. In my case, it's defined to expose <span class="code" style="background-color:white">src/data</span>. So I'll start by placing my speaking folder, filled with all the images for my speaking engagements, within that scope. </p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":3099,"align":"center","width":243,"height":299} -->
<div class="wp-block-image"><figure class="aligncenter is-resized"><img src="https://tenmilesquare.com/wp-content/uploads/2019/01/Screen-Shot-2019-01-08-at-12.29.58-PM.png" alt="" class="wp-image-3099" width="243" height="299"/></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>From there, I need to make sure that the file names defined in <span class="code" style="background-color:white">speaking.yaml</span> are matched with the appropriate path so that GraphQL can find the image files. To make this work, I actually changed the data in my yaml file slightly. Instead of just referencing the file name, I put a relative path. The path to the image is relative to the location of the <span class="code" style="background-color:white">speaking.yaml</span> file (NOT the filesource path defined, this one tripped me up).</p>
<!-- /wp:paragraph -->

```yaml
image: speaking/kcdc.jpg
```

<!-- wp:paragraph -->
<p>Now, I can turn my attention to GraphQL. Right now, <span class="code" style="background-color:white">image</span> is just a string. I can query it like this.
<!-- /wp:paragraph -->

```graphql
{
    allSpeakingYaml (sort: {fields: [index], order: DESC}) {
        edges {
            node {
                conference
                year
                url
                date
                image
            }
        }
    }
}
```

<!-- wp:paragraph -->
<p>However, the above doesn't do what I want. It returns a string of the relative path, e.g. <span class="code" style="background-color:white">"speaking/kcdc.jpg"</span>. However, I really like that I can query image as part of the speaking data itself. I'd like to keep that behavior. It turns out, I can. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>I can use <span class="code" style="background-color:white">gatsby-image</span> features inside the query. When the query runs, the relative path will point to the location of the image file and the resulting query processes the file as an image for display. </p>
<!-- /wp:paragraph -->


```graphql
{
    allSpeakingYaml (sort: {fields: [index], order: DESC}) {
        edges {
            node {
                conference
                year
                url
                date
                image {
                    childImageSharp {
                        fluid {
                            ...GatsbyImageSharpFluid
                        }
                    }
                }
            }
        }
    }
}
```

<!-- wp:paragraph -->
<p>Now, when I loop through my speaking data with a JSX map, there is an image in each of those objects instead of a string. So I want to use JSX to access those images. As it turns out `g<span class="code" style="background-color: white;">atsby-image`</span> has its own tag that I can use, so I'll import that.</p>
<!-- /wp:paragraph -->

```jsx
import Img from "gatsby-image";
```

<!-- wp:paragraph -->
<p>My first instinct is to write something like this.</p>
<!-- /wp:paragraph -->

```jsx
<Img className="selfie" fluid={node.image} alt={node.conference}/>
```

<!-- wp:paragraph -->
<p>Unfortunately, that doesn't work. The page rendered with an icon where the image should be. For some reason this took me more than a minute to crack, but the answer is relatively simple. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In many of our GraphQL queries the structure of the query is based on the structure of our yaml data. So the return object structure looks roughly the same as the yaml file. We saw an exception to that rule when we added the <span class="code" style="background-color:white">node</span> and <span class="code" style="background-color:white">edge</span> objects to access the first level of the yaml results. This is the same thing, I just didn’t notice it. The actual processed image is at the <span class="code" style="background-color:white">...GatsbyImageSharpFluid</span> level. What I was accessing with <span class="code" style="background-color:white">node.image</span> was not the processed image. So the resulting successful code is</p>
<!-- /wp:paragraph -->

```jsx
<Img className="selfie" fluid={node.image.childImageSharp.fluid}
alt={node.conference}/>
```

<!-- wp:heading {"level":3} -->
<h3 id="mce_46">Single Image Query</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now I want to go back and optimize the “easy” use case. The first thing to do is to remove the import of the file and set it up as a GraphQL query that runs through <span class="code" style="background-color:white">gatsby-image</span> processing. This will look a lot like what I did for the series of speaking images. </p>
<!-- /wp:paragraph -->

```jsx
export const query = graphql`
  query {
   <strong> file(relativePath: { eq: "headers/headshot.jpg" }) {
      childImageSharp {
        <strong> fixed(width: 125, height: 125) {
          ...GatsbyImageSharpFixed
        }
      }
    }
  }
`
```

<!-- wp:paragraph -->
<p>There are a couple of things to note here. Based on my previous code I would expect the relative path I need to be relative to the file the code sits in, in this case that's index.js. However, that doesn't work. The relative path is actually based on the line of code we put in the <span class="code" style="background-color:white">`gatsby-source-filesystem`</span> config, which points to <span class="code" style="background-color:white">src/data</span>. That actually took me a bit to recognize. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Another thing to note in the query is that we’re using <span class="code" style="background-color:white">GatsbyImageSharpFixed</span> instead of fluid. To be honest, this should also be a fluid image and in my final site it will be. However, for the purposes of testing out all the features the image plugin offered, I wanted to try both. In <span class="code" style="background-color:white">`gatsby-image`</span>, fluid images are meant for images that don’t have a finite size depending on the screen, where as other images are fixed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After figuring out all of those little idiosyncrasies I can finally display this image using JSX. This is more or less the same as what I did to display my speaking data. The only difference is that I've chosen to process the image as fixed instead of fluid, so I need to reference it as such. </p>
<!-- /wp:paragraph -->

```jsx
<Img className="headshot" fixed={data.file.childImageSharp.fixed}
alt="headshot"/>
```

<!-- wp:heading {"level":3} -->
<h3 id="mce_31">Aspect Ratio</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This is a good time to go on a quick tangent. In the process of trying to style my images I noticed a surprising number of complexities. As it turns out, each image has some implicit styling that comes with the wrapper the processor puts around it. This was messing with all kinds of CSS I had attempted to use. This could be a whole other post, but I discovered one neat trick as part of my never ending googling for the answer. The plugin supports sizes where you can set an aspect ratio. This can be used for fixed or fluid processed images, it doesn't matter.</p>
<!-- /wp:paragraph -->

```jsx
<Img sizes={{...data.banner.childImageSharp.fluid, aspectRatio: 21/9}}/>
```

<!-- wp:heading {"level":3} -->
<h3 id="mce_44">Static Query</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The next thing I want to do is handle my header images. In my previous site  I had a Header.js file that was included in my layout and rendered on all my pages. So I want to have the same reusable component here. I'll start by using the same code I used to render my headshot above. Well, that doesn't work. As it turns out,  the reason for this is that there are restrictions to what GraphQL can do on non-page components. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The way to solve this is to use a Static Query. The first thing I need to do is change the structure of my Header.js component. </p>
<!-- /wp:paragraph -->

```jsx
export default () => (
 <StaticQuery 
    query={graphql`
    query {
      file(relativePath: { eq: "headers/default.jpg" }) {
        childImageSharp {
          fixed(width: 125, height: 125) {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `}
    render={data => (
      <section id="header">
         <h2>LAURIE BARTH</h2>
         <Img fixed={data.file.childImageSharp.fixed} />
      </section>
    )}
  />
)
```

<!-- wp:paragraph -->
<p>Instead of a query constant and data that references the result, I have to use a static query directly in the JXS code and then reference it. Note that the query language didn’t change and neither did the <span class="code" style="background-color: white;">Img</span> tag syntax, the only change was the location of the query and the usage of the StaticQuery tag to wrap it.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 id="mce_45">Multiple Queries and Aliasing</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The last use case I need to figure out is how to handle a situation where I have multiple queries in the same file/page. I may or may not need this in the final site, but it's a worthwhile exercise.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In this case I want to query for all my data in my <span class="code" style="background-color: white;">speaking.yaml</span> file AND I want to query for my headshot separately. The answer to this problem is to use aliasing, but I found most write ups on this topic explained the concept but missed some gotchas. The first thing to know is that an alias is assigning a name to a query. Below is a simple example.</p>
<!-- /wp:paragraph -->

```graphql
talks: allSpeakingYaml(sort: {fields: [index], order: DESC}) {
        edges {
            node {
                conference
                year
                url
                date
                image {
                    childImageSharp {
                        fluid {
                            ...GatsbyImageSharpFluid
                        }
                    }
                }
            }
        }
    }
}
```

<!-- wp:paragraph -->
<p>When you do that, you’ve changed the reference to that object in your JXS. While it was previously referenced as </p>
<!-- /wp:paragraph -->

```jsx
{data.allSpeakingYaml.edges.map(({ node }) => ())
```

<!-- wp:paragraph -->
<p>giving it an alias does not add a level of complexity to the response object, it just replaces it. So you end up with the same structure referenced as</p>
<!-- /wp:paragraph -->

```jsx
{data.talks.edges.map(({ node }) => ())
```

<!-- wp:paragraph -->
<p>The top-level object name of data is implicit. This is important because when I added multiple queries to this, I was still only passing in the data object</p>
<!-- /wp:paragraph -->

```jsx
const SpeakingPage = ({ data}) => {}
```

<!-- wp:paragraph -->
<p>everything else was referenced from that top-level return
name.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>With that understanding, I can combine two queries and use aliasing to distinguish between them. </p>
<!-- /wp:paragraph -->

```graphql
{
    allSpeakingYaml (sort: {fields: [index], order: DESC}) {
        edges {
            node {
                conference
                year
                url
                date
                location
                image {
                    childImageSharp {
                        fluid {
                            ...GatsbyImageSharpFluid
                        }
                    }
                }
                talks {
                    title 
                    video
                }
            }
        }
    }
    banner: file(relativePath: { eq: "headers/default.jpg" }) {
      childImageSharp {
        fluid {
          ...GatsbyImageSharpFluid
        }
      }
  }
}
```

<!-- wp:paragraph -->
<p>Notice that I decided I didn’t need to alias the first query. This is allowed; there is no requirement that all your queries use aliasing. So I reference the speaking data array the same way I was before.</p>
<!-- /wp:paragraph -->

```jsx
{data.allSpeakingYaml.edges.map(({ node }) => ())
```

<!-- wp:paragraph -->
<p>Then I access my image using my alias name, banner. </p>
<!-- /wp:paragraph -->

```jsx
<Img fluid={data.banner.childImageSharp.fluid} />
```

<!-- wp:heading {"level":3} -->
<h3 id="mce_5">The End</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>So that's it. I've now optimized all my images. This post included a number of different possible use cases, so don't feel as if you need to explore them all. Pick the examples and tips that apply to your implementation.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In my case, my site should now pass a Lighthouse audit with a much higher grade and this blog series comes to a close. Hopefully these posts were helpful for those who ran into the same micro problems that I did. My next challenge is to remove the starter template I used and make a far more responsive design. So until next time!</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3> Bonus Error </h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>When I went back and changed my images from <span class="code" style="background-color: white;">fixed</span> to <span class="code" style="background-color: white;">fluid</span> I received an error.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":3607} -->
<figure class="wp-block-image"><img src="https://tenmilesquare.com/wp-content/uploads/2019/02/Screen-Shot-2019-02-18-at-11.46.03-AM-1024x212.png" alt="" class="wp-image-3607"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Despite its appearance, solving this doesn't actually require flushing any kind of cache. In reality, it has to do with incompatible references. I triggered it because I had changed my query to process the image as <span class="code" style="background-color: white;">fluid</span> but the JSX key was still set to <span class="code" style="background-color: white;">fixed</span>.</p>
<!-- /wp:paragraph -->