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">📅 {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`,
],
}