Search code examples
graphqlmarkdowngatsbystyled-componentsyaml-front-matter

Gatsby: set an image background through frontmatter, GraphQl and Styled-components


I know this problem sounds a bit complex but it's not.
I'll try my best to explain it in a simple way:

  • I'm making a list of blog posts for the homepage of my Gatsby website.
  • The list is made of "boxes", every box that links to a post has a background-image.

  • I pass this background-image to a styled-component, it gets the image from a prop value that I inserted in the main < div > element (you'll find the example bellow).

  • It works fine, till I try use an image from my local folder under src (instead of using an online link that I simply putted on frontmatter).


Here's what I did in the past, and worked:
I put the url of the image on the frontmatter of the markdown file:

---
slug: "/post/my-post"
 [...]
imghero: "https:/path/to/image-online.jpg" 
---

Then query it with graphql:

const LISTING_QUERY = graphql`
        query BlogPostListing {
            allMarkdownRemark(limit: 10, sort: {
                order: DESC,
                fields: [frontmatter___date]
            }) {
            edges {
                node {
                excerpt
                frontmatter {
                    title
                    slug
                    date(formatString: "MMMM DD, YYYY")
                    imghero
                }
                }
            }
            }
        }
`

After that I insert the {node.frontmatter.imghero} it on a prop on the main div:

const Listing = () => (
    <StaticQuery 
        query={LISTING_QUERY} 
        render={({allMarkdownRemark}) => ( 
            allMarkdownRemark.edges.map(({node}) => (
                <Article img_background={node.frontmatter.imghero} key={node.frontmatter.slug}>
                [... etc ...]
                </Article>
            ))
        )}
    />
)

export default Listing

And finally I call that img_background prop in the styled-component:

const Article = styled.article`
    background-image: url(${props => props.img_background};);
    [... etc ...]
`

This method works.


Now I want to get the image from my "images" folder and not from a random url.

  • I installed gatsby-remark-images
  • Set it on gatsby-config.js and put the path of some image on frontmatter.
  • Test everything with http://localhost:8000/___graphql (and worked)
  • Insert the additional query throught graphql:

    [...]
    frontmatter {
    date(formatString: "DD MMMM, YYYY")
    title
    imghero
    hero {
        childImageSharp{
            fluid(maxWidth: 630) {
                ...GatsbyImageSharpFluid
            }
        }
    }
    [...]
    
  • I modify the node on the component with the new path:

    <Article img_background={node.frontmatter.hero.childImageSharp.fluid} [...]> 
        [...] 
    </Article>
    
  • Gatsby Develop compiles fine.

But then my homepage is completely white.
And the console of the browser says that node.frontmatter.hero is "null". I don't know that else to do.

Thanks for the help.


Solution

  • I think a bit more info is necessary to resolve your issue, none of the thing you listed out looks wrong in itself. However so many folks got tripped off by image handling in gatsby that I'm writing a check list. It's meant to be generic, but I think no.5, 8, 9, 12 might help you locate the problem.


    Using image with gatsby-transformer-remark + gatsby-transformer-sharp troubleshooting

    Setup

    1. Is there any error at all? Sometimes gatsby will still compile successfully despite something's wrong. Check the console for anything that's... red.
    2. Did you restart gatsby i.e turn it on and off again? Try removing cache & public folder (.cache and public) if you suspect something's wrong with them.
    3. Did you list your image folder, or any of its parent folders in gatsby-source-filesystem?
    4. In your frontmatter, is the path to the image relative to the markdown file itself? i.e path starts with a dot ./relative/path/to/image.png
    5. Does all markdown has a hero field in frontmatter? If a file doesn't have a hero field, it will be null.
    6. If the image path in frontmatter is not relative or doesn't link to a file, it'll be treated as a regular string.

    Query & Fragments

    1. Does your query work? Test your query in http://localhost:8000/___graphql. Make sure the image field show up as a File node. Try something simple like
    query {
      allMarkdownRemark {
        frontmatter {
          title
          hero {
            id
            name  <-- just enough to know the file exists
          }
        }
      }
    }
    

    If your hero shows up as a string, something's wrong, check the setup again.

    1. Are you using fragments? Currently fragments can't be test in the graphiql tool, so you might need to find the definition of that fragment and test it manually. Here's a list of the default ones that come with gatsby-transformer-sharp and their definitions.

    2. If you're using a custom fragment, make sure to define & export it somewhere.

    Usage

    1. If image doesn't show up in the browser, inspect & try to find what's shown up in place of your image.
    2. Are you using gatsby-image? If so, make sure you're passing in something it can work with.
    3. Make sure your image component receives what it should. If your component's expecting a path, don't pass in an object, like result of a fragment.

    Some side note

    • gatsby-remark-images only handle relative links in markdown image & html <img>, so if your image is living in frontmatter, it won't do anything.