Search code examples
graphqlgatsbynetlify-cmsgatsby-plugin-image

How do I query a image via a json file with an image path with graphql in Gatsby.js?


In Gatsby I'm trying to create a query with Graphql to query an image. The image location is set in a homepage.json file (this is being managed by Netlify CMS, so it is dynamic):

{
  "homepage_text": "Here goes homepage text",
  "homepage_background": "/images/homepage.jpg"
}

The images are located in src/images/

In Gatsby, there are 2 ways of displaying an image:

  • StaticImage (which doesn't work for me since the image is dynamic)
  • GatsbyImage

My only way is to use GatsbyImage I suppose, I query the homepage information with the following query:

query HomepageQuery {
  file(ext: {eq: ".json"}, name: {eq: "homepage"}, childImageSharp: {}) {
    childSettingsJson {
      homepage_background
      homepage_text
    }
  }
}

According to the gatsby-plugin-image docs https://www.gatsbyjs.com/plugins/gatsby-plugin-image I need to add the following to the query (childImageSharp and gatsbyImageData). But that's not possible with my example since it's not the actual image but rather the string that points to the location of the image. What can I change in my code/query to make it work along with GatsbyImage? (or another suggestion)

   homepage_background {
      childImageSharp {
        gatsbyImageData(width: 200)
      }
    }

My config.yml:

backend:
  name: git-gateway
  branch: master # Branch to update (optional; defaults to master)

media_folder: static/images
public_folder: /images

collections:
  - name: "settings"
    label: "Settings"
    delete: false # Prevent users from deleting documents in this collection
    editor:
      preview: false
    files:
      - name: "general"
        label: "General"
        file: "/content/settings/general.json"
        description: "General"
        fields:
          - { label: "Website title", name: "site_title", widget: "string" }
          - { label: "Favicon", name: "favicon", widget: "image" }
      - name: "homepage"
        label: "Home"
        file: "/content/settings/homepage.json"
        fields:
          - { label: "Homepage Text", name: "homepage_text", widget: "string" }
          - {
            label: "Homepage Background Image",
            name: "homepage_background",
            widget: "image",
            required: false,
          }

Plugins from my gatsby-config.js:

plugins: [
    `gatsby-plugin-image`,
    `gatsby-plugin-netlify-cms`,
    `gatsby-transformer-json`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `settings`,
        path: `${__dirname}/content/settings`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          `gatsby-remark-images`,
          `gatsby-remark-responsive-iframe`,
          `gatsby-remark-prismjs`,
        ],
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    `gatsby-plugin-postcss`,
    `gatsby-plugin-sass`
  ],

Solution

  • As you pointed out, in order to use GatsbyImage you need to provide a valid node (childImageSharp) and in order to create it, you need to tell Gatsby where those images are.

    To do so, you need to add a new instance of the gatsby-source-filesystem pointing to that path:

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

    Now, when running gatsby develop, in your GraphiQL environment (localhost:8000/___graphql) you should see a new node called allImageSharp or allFile which can be filtered by sourceInstanceName (stands for the name in the gatsby-source-filesystem):

      allFile(filter: { sourceInstanceName: { eq: "uploads" } }) {
        edges {
          node {
            childImageSharp {
              gatsbyImageData
            }
          }
        }
      }
    

    There's a known issue where NetlifyCMS is not properly setting the relative paths properly and Gatsby is not able to infer directly the image node, hence the homepage_background still stands for a string rather than a Gatsby Image node data. Check https://github.com/danielmahon/gatsby-remark-relative-images


    Disclaimer: ideally, NetlifyCMS is meant to source from a Markdown file, not a JSON, I don't know how this would behave in this approach.