javascriptreactjscontent-management-systemgatsbygatsby-image

Forestry + Gatsby Image - reference image from JSON files


I'm looking into using Forestry with Gatsby (and use gatsby-plugin-image to optimize the images), but I'm stuck on how to get it working and not sure if it's even possible.

  1. The first approach I tried (not working with Gatsby Image) is:

The image path is set in JSON files (to make all page content editable) and the images are uploaded to the static/uploads folder because Forestry requires an absolute path for the images:

content/pages/home.json:

{
  "title": "Home",
  "hero_image": "../../uploads/hero_image.png",
  "hero_image_alt": "An image",
  ...
}

--> This approach will not make it queryable in GraphQL by Gatsby so I can only use it in a normal img tag:

pages/index.js:

import { useStaticQuery, graphql } from "gatsby"
...
const { allPagesJson } = useStaticQuery(
    graphql`
      {
        allPagesJson {
          nodes {
            hero_image_alt
            hero_image
          }
        }
      }
    `

const data = allPagesJson.nodes[0]
<img src={data.hero_image} alt={data.hero_image_alt} />
  1. Second approach I tried (queryable but still not working) is:

The images are uploaded to content/images and then a relative path is added in the JSON files:

content/pages/home.json:

{
  "title": "Home",
  "hero_image": "../images/hero_image.png",
  "hero_image_alt": "A picture"
}

--> This approach makes it queryable, so I'd think I can use it in the GatsbyImage component, but it always returns a 404 error:

pages/index.js:

import { useStaticQuery, graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
...
const { allPagesJson } = useStaticQuery(
    graphql`
      {
        allPagesJson{
          nodes {
            hero_image_alt
            hero_image {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
      }
    `
  )
...
const data = allPagesJson.nodes[0]
const hero_image = getImage(data.hero_image)
...
<GatsbyImage image={hero_image} alt={data.hero_image_alt} />

This returns the error: GET http://localhost:8000/static/130e6fa61e2ebe523785c187e562a5f8/61d51/hero_image.webp 404 (Not Found)

I've been struggling with this all afternoon and not sure what else I can try to get it working with Forestry.

My basic requirements are that I need to be able to make all page content editable (text/images) for users instead of only being able to create posts + optimize the images with GatsbyImage so if there's a better way in general to make that happen I'm also all ears.


Solution

  • The first approach I tried (not working with Gatsby Image) is:

    This approach will not make it queryable in GraphQL by Gatsby so I can only use it in a normal img tag

    That's not true at all. If you store static images inside your project, you need to tell Gatsby where those images are to allow it to create the proper nodes to fetch (to use along with GatsbyImage). This is done by setting a filesystem pointing the path where those images are stored.

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/uploads/`,
      },
    },
    

    Note: tweak it to match your uploads path. In this case, the uploads folder will be "parsed" by Gatsby and if there are images there, will create the proper nodes. Once that, using the GraphiQL playground (localhost:8000/___graphql) you will find your images nodes to fetch.

    With the second approach, the node is added because /images is a default filesystem for image assets so it's adding what I've just explained automatically. Check those configurations in gatsby-config.js.

    Regarding the second approach issue, the 404, the workaround seems good despite you may be missing something at data or hero_image declaration. Your GatsbyImage component looks good but seems that the data is empty.

    ...
    const data = allPagesJson.nodes[0]
    console.log(data)
    const hero_image = getImage(data.hero_image)
    console.log(hero_image )
    ...
    <GatsbyImage image={hero_image} alt={data.hero_image_alt} />
    

    Try sharing the full snippet.