1
votes

I'm using GraphQL from within a Gatsby project. I have a set of markdown files for a blog-like section of the site. In the frontmatter of each markdown file, there's an image property.

What I'd like to do is use Gatsby's fine image api to load the image in the frontmatter. When viewing an individual post (the ones created via createPage api), this works just fine because I can provide the frontmatter.image in the context. Here's what that query looks like.

export const pageQuery = graphql`
  query($slug: String!, $image: String) {
    markdownRemark(frontmatter: { slug: { eq: $slug } }) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        slug
        title
        image
      }
    }
    coverImage: file(relativePath: { eq: $image }) {
        childImageSharp {
          fluid(maxWidth: 1440) {
            ...GatsbyImageSharpFluid
          }
        }
      }
  }
`

On my index page where I'm displaying all these posts though, I want to display a smaller version of this image. I can get the image from the front matter easy enough, but I'm not sure how to integrate that into the query.

export const pageQuery = graphql`
  query {
    allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
      edges {
        node {
          id
          excerpt(pruneLength: 250)
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            slug
            title
            image # <--- want to use this in a file query
          }
        }
      }
    }
  }
`

As far as I understand, I can't use string interpolation in a static query in the component where the image is actually used, so I need to get it here in the page query. Is what I'm trying to do possible? Is there a better way to handle this?

1
Just to clarify - you basically want to process your frontmatter images with Sharp (to then use with gatsby-image)? The way to go is via GraphQL foreign key relationships. I can explain more in an answer if this is what you're looking for.Robin Métral
@RobinMétral Essentially yes, that's what I'm trying to doScribblemacher

1 Answers

2
votes

This "link" between your frontmatter's image string and an actual image file node (processed with Sharp) is called a foreign-key relationship.

Creating foreign-key relationships in Gatsby

There are two ways of doing this:

  1. Using mappings in gatsby-config.js
  2. Using a GraphQL @link directive through Gatsby's schema customization (from v2.2)

I recommend the second option, since it's a more GraphQL way of doing things, and happens in gatsby-node.js where most node operations are taking place. However, if you're starting out with Gatsby and GraphQL, the first option might be easier to set up.

Implementing the @link directive in gatsby-node.js

In your case, using the @link GraphQL directive, you would probably end up with something like this in your gatsby-node.js:

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  const typeDefs = [
    `type MarkdownRemark implements Node { frontmatter: Frontmatter }`,
    `type Frontmatter {
      # you may need to adapt this line depending on the node type and key
      # that you want to create the relationship for
      image: File @link(by: "relativePath")
    }`
  ]
  createTypes(typeDefs)
}

If you want to see an example in the wild, check out gatsby-node.js in robinmetral/eaudepoisson.com.

Query processed images via your frontmatter

Finally, you'll be able to query like this:

{
  allMarkdownRemark {
    edges {
      node {
        frontmatter {
          date
          slug
          title
          # image now points to the image file node
          image {
            childImageSharp {
              fluid(maxWidth: 1024) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
      }
    }
  }
}