skip to Main Content

I built a blog with Gatsby and Tailwind using markdown for blog posts. When querying the data using graphql, I can’t get any of the images to display. My images are stored within the src/ directory in an images/ folder. My posts are inside of a pages/ folder within that same directory. At one point the site displayed ALL of the images including the ones in markdown, but wouldn’t work when deployed to Netlify. I’ve gotten the site to deploy, but now none of my images are showing and I’ve tried everything to get them back. I’ve also tried using gatsby-image (fixed and fluid) and still nothing.

This is my first project with gatsby, markdown, and graphql. Currently, the deployed site nikkipeel.netlify.app shows the proper path on the blog page for posts when inspected using devtools (../images/example.jpg), but still no image actually displays. 🤷‍♀️

Github repo: gatsby-blog

project structure:

|-- /public
|-- /src
    |-- /components
    |-- /pages
       |-- /post-one
          |--index.md
       |-- /post-two
          |--index.md
       |-- /post-three
          |--index.md
    |-- /templates
       |-- blog-post.js
    |-- /images

|-- /static
|-- gatsby-config.js
|-- gatsby-node.js
|-- gatsby-ssr.js
|-- gatsby-browser.js

frontmatter for a blog post (index.md) –

---
path: "/create-a-blog-with-react-and-sanity"
date: "2021-01-10"
title: "Create a blog with React and Sanity"
description: "Create a technical blog built with React, TailwindCSS, and Sanity then deploy it using Github and Netlify"
category: "React"
author: "Nikki Peel"
authorImage:  ../images/selfie.png
image: ../images/sanity-blog-collage.jpg
---

Blog.js with Graphql query for displaying all posts:

import React from "react"
import { graphql } from 'gatsby'
import Layout from "../components/layout"
import Link from 'gatsby-link';
import SEO from "../components/seo"

const BlogPage = ({ data }) => (
  <Layout>
    <SEO title="Blog" />
    <main className="bg-brown text-white h-auto p-12">
            <section className="container mx-auto">
                <h1 className="text-4xl mono pl-4">Latest Blog Posts</h1>
                <h2 className="text-lg mb-12 pl-4">Welcome to my page of blog posts</h2>


                <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 justify-center mx-auto md:gap-8 mb-24"> 
                {data.allMarkdownRemark.edges.map(post => (
                   <article>
                   <Link to={post.node.frontmatter.path}>
    
                   <div className="block lg:h-64 relative leading-snug" key={ post.node.id }>
                   <img src={post.node.frontmatter.image} alt="" className="lg:block w-full items-center lg:h-full lg:object-cover lg:object-top relative lg:absolute"/> 
                       <span className="block relative lg:h-full lg:flex lg:items-end ">
                           <h3 className="lg:bg-gray-800 lg:bg-opacity-75 text-white text-xl font-semibold lg:px-3 lg:py-4 rounded text-left">{post.node.frontmatter.title}</h3>
                       </span>
                      <div className="mt-4 mb-8"> 
                           <p className="text-base mb-4">{post.node.frontmatter.description}</p>
                           <span id={post.node.frontmatter.category} className="text-black font-semibold text-sm py-2 px-4 mr-2 rounded">{post.node.frontmatter.category}</span>
                           <small className="text-base ml-2">&#128197; {post.node.frontmatter.date}</small>
                       </div> 
                   </div>
                   </Link>
               </article>
     ))}

               
                </div>
            </section>
        </main>
  </Layout>
)

export const pageQuery = graphql`
    query BlogIndexQuery {
            allMarkdownRemark  (sort: { fields: [frontmatter___date], order: DESC }){
                edges {
                    node {
                        id
                    frontmatter {
                        path
                        title
                        description
                        date
                        category
                        image
                    }
                }
            }
        }
    }
`;

export default BlogPage; 

And for Single Posts – blog-post.js:

import React from 'react';
import { graphql } from 'gatsby'
import Link from 'gatsby-link';
import Layout from '../components/layout';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';

export default function Template({ data }) {
    const post = data.markdownRemark

    return (
        <Layout>
              <main className="container bg-brown min-h-screen p-4 md:p-12">
            <Link to="/blog" exact className="text-white text-base items-center"><FontAwesomeIcon icon={faChevronLeft} className="mr-4"></FontAwesomeIcon> Back to Blog</Link>
            <article className="container text-white mx-auto rounded-lg mt-4">
                <header className="relative">
                    <div className="absolute h-full w-full flex items-center justify-center p-8">
                        <div className="bg-white text-brown bg-opacity-75 rounded p-4 md:p-12">
                            <h1 className="mono text-3xl mb-4">
                                {post.frontmatter.title}
                            </h1>
                            <div className="flex justify-center text-brown">
                                <img src={post.frontmatter.authorImage} alt="" className="w-10 h-10 rounded-full"/>
                                <p className="mono flex items-center pl-4 text-xl">{post.frontmatter.author}</p>
                            </div>
                            <p className="text-base font-semibold mt-4 text-center">Published on <strong>{post.frontmatter.date}</strong></p>
                        </div>
                    </div>
                    <img src={post.frontmatter.image} alt={post.frontmatter.title} className="w-full object-cover object-left-top rounded-t" style={{ height: "400px", width: "100%"}}/>
                </header>
                <div className="break-words px-4 lg:px-16 py-12 lg:py-20 prose lg:prose-xl max-w-screen leading-normal">
                    <div dangerouslySetInnerHTML={{ __html: post.html }} />
                </div>
            </article>
        </main>
        </Layout>
    )
}

export const postQuery = graphql`
    query BlogPostByPath($path: String!) {
        markdownRemark(frontmatter: { path: { eq: $path } }){
            html
            frontmatter {
                path
                title
                date
                author
                authorImage 
                image
            }
        }
    }
`

When using the graphiql playground, the proper image path is retrieved for blog.js but not for blog-post.js (individual posts):

blog.js query:

{
  "data": {
    "allMarkdownRemark": {
      "edges": [
        {
          "node": {
            "frontmatter": {
              "path": "/customizing-the-scrollbar-with-css",
              "title": "Customizing the Scrollbar with CSS",
              "description": "Learn how to apply custom styling to the scrollbar on your project with pure CSS",
              "date": "2021-01-28",
              "category": "CSS",
              "image": "../images/scrollbar.png"
            }
          }
        },

blog-post.js query:

{
  "errors": [
    {
      "message": "Variable "$path" of required type "String!" was not provided.",
      "locations": [
        {
          "line": 1,
          "column": 24
        }
      ],
      "stack": [
        "GraphQLError: Variable "$path" of required type "String!" was not provided.",
        "    at _loop (C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\graphql\execution\values.js:92:17)",
        "    at coerceVariableValues (C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\graphql\execution\values.js:119:16)",
        "    at getVariableValues (C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\graphql\execution\values.js:48:19)",
        "    at buildExecutionContext (C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\graphql\execution\execute.js:184:61)",
        "    at executeImpl (C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\graphql\execution\execute.js:89:20)",
        "    at execute (C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\graphql\execution\execute.js:64:35)",
        "    at C:\Users\npeel\Microsoft VS Code\gatsby-blog-main\gatsby-blog-main\node_modules\express-graphql\index.js:152:16",
        "    at runMicrotasks (<anonymous>)",
        "    at processTicksAndRejections (internal/process/task_queues.js:93:5)"
      ]
    }
  ],
  "extensions": {}
}

gatsby-node.js –

I received an error when adding ‘image’ and ‘authorImage’ to frontmatter here

const path = require('path');

exports.createPages = ({actions, graphql}) => {
    const { createPage } = actions

    const postTemplate = path.resolve('src/templates/blog-post.js');

    return graphql(`
        {
            allMarkdownRemark{
                edges {
                    node {
                        html
                        id
                    frontmatter {
                        path
                        title
                        date
                        author
                        category
                        description
                    }
                    }
                }
            }
        }
    `).then(res => {
        if(res.errors) {
            return Promise.reject(res.errors)
        }

        res.data.allMarkdownRemark.edges.forEach(({node}) => {
            createPage({
                path: node.frontmatter.path,
                component: postTemplate
            })
        })
    })
}


// for RSS feed:
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}

gatsby-config.js –

module.exports = {
  siteMetadata: {
    title: `Nikki Peel - Blog`,
    description: `Technical blog created with Gatsby and Markdown`,
    author: `Nikki Peel`,
    siteUrl: `https://nikkipeel.netlify.app`,
  },
  plugins: [
    `gatsby-transformer-remark`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-catch-links`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `pages`,
        path: `${__dirname}/src/pages`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },

    {
      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/blog-logo.png`, // This path is relative to the root of the site.
      },
    },
    `gatsby-plugin-feed`,
    `gatsby-plugin-postcss`,
    `gatsby-plugin-fontawesome-css`,
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // `gatsby-plugin-offline`,
  ],
}

2

Answers


  1. Chosen as BEST ANSWER

    I was able to get the images to load by referencing an external source in the markdown files but still can't access them by file path 🤷‍♀️ I'm still researching and working on this issue

    ---
    path: "/post-three"
    date: "2020-11-23"
    title: "My Third Gatsby Post"
    description: "This is my third markdown post with gatsby"
    category: "Tailwind"
    author: "Nikki Peel"
    authorImage: https://i.imgur.com/qyIekvV.png
    image: https://i.imgur.com/lKnOCsT.jpg
    ---
    

  2. As you can see in the documentation, the when dealing with markdown plus images, the paths should be relative to the markdown file itself so:

    ---
    path: "/create-a-blog-with-react-and-sanity"
    date: "2021-01-10"
    title: "Create a blog with React and Sanity"
    description: "Create a technical blog built with React, TailwindCSS, and Sanity then deploy it using Github and Netlify"
    category: "React"
    author: "Nikki Peel"
    authorImage: /gatsby-blog/images/selfie.png
    image: /gatsby-blog/images/sanity-blog-collage.jpg
    ---
    

    From post-one: https://github.com/nikkipeel/gatsby-blog/blob/main/src/pages/post-one/index.md

    Should become:

    ---
    path: "/create-a-blog-with-react-and-sanity"
    date: "2021-01-10"
    title: "Create a blog with React and Sanity"
    description: "Create a technical blog built with React, TailwindCSS, and Sanity then deploy it using Github and Netlify"
    category: "React"
    author: "Nikki Peel"
    authorImage: ../../images/selfie.png
    image: ../../sanity-blog-collage.jpg
    ---
    

    Note the relativity of both images (../../images/selfie.jpg). This will allow Gatsby to create a valid GraphQL node and it will display the childImageSharp node in the GraphQL playground (localhost:8000/___graphql).

    Field "image" must not have a selection since type "String" has no
    subfields. This can happen if you e.g. accidentally added { } to the
    field "image". If you didn’t expect "image" to be of type "String"
    make sure that your input source and/or plugin is correct.

    Unlike it may seem, this is a good error because it’s pointing that Gatsby is trying to create nodes from your markdown files (i.e: your paths are well referenced now) and you will be able to use gatsby-image. I’ve realized that you are missing some plugins, according to the docs.

    Add the gatsby-transformer-remark and the gatsby-remark-images plugin.

    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 800,
            },
          },
        ],
      },
    },
    

    I wouldn’t put the markdown files in the /pages folder by Gatsby to avoid potential issues. Gatsby is a folder-structure based routing, or in other words, Gatsby infers the internal structure of the /pages folder to create the routing and the paths so it’s better to avoid mixing stuff.

    Your pages can be stored inside any folder if you set the gatsby-source-filesystem accordingly. This will allow Gatsby to create GraphQL nodes from those markdown files.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search