How to allow optional sharp image in graphql gatsby?
Asked Answered
E

1

8

I typically have frontmatter that will have an array of objects, inside each object will be an image which will reference a string of a file relative to the markdown file.

The problem is, the array could sometimes be empty, meaning graphql will have to work out what the schema is by setting all the values to non-null, I have been able to do this with simple types such as strings using Gatsby's createSchemaCustomization, but I want to be able to declare a string that references an image to use Image Sharp (so gatsby-transformer-sharp can compress the image before the component receives it).

It doesn't seem like anywhere on the Gatsby documentation or image sharp plugin that there is a schema type for this.

I tried using File! as a type which works when the array is empty but when you actually try to reference real images it simply returns { image: childImageSharp: null } meaning gatsby-transformer-sharp doesn't run on them like it does when File! isn't decalared.

Below is how my schema has been declared:

exports.createSchemaCustomization = ({ actions }) => {
    const { createTypes } = actions;
    const typeDefs = `
        type MarkdownRemark implements Node {
            frontmatter: Frontmatter
        }
        type Frontmatter {
          features: [Feature!]!
        }
        type Feature {
            title: String!
            description: String!
            image: File!
        }
    `;

    createTypes(typeDefs);
};

This is my graphql query:

export const query = graphql`
    query HomeQuery($path: String!) {
        markdownRemark(frontmatter: { path: { eq: $path } }) {
            html
            frontmatter {
                features {
                    title
                    description
                    image {
                        childImageSharp {
                            fluid(maxWidth: 800) {
                                ...GatsbyImageSharpFluid
                            }
                        }
                    }
                }
            }
        }
    }
`;

And my markdown file which returns the array of objects of features, image being the string which should create a fluid image sharp object.

---
path: '/'
features:
    - title: Barns
      description: Praesent commodo cursus magna vel scelerisque nisl consectetur et. Nullam id dolor id nibh ultricies vehicula ut id elit.
      image: features-001.png
    - title: Private Events
      description: Praesent commodo cursus magna vel scelerisque nisl consectetur et. Nullam id dolor id nibh ultricies vehicula ut id elit.
      image: features-002.png
    - title: Food and Drinks
      description: Praesent commodo cursus magna vel scelerisque nisl consectetur et. Nullam id dolor id nibh ultricies vehicula ut id elit.
      image: features-003.png
    - title: Spa
      description: Praesent commodo cursus magna vel scelerisque nisl consectetur et. Nullam id dolor id nibh ultricies vehicula ut id elit.
      image: features-004.png
---

As an overview, as soon as I remove the File! on the createSchemaCustomization all the images show up, but the build will break as soon as the array is empty.

Erewhile answered 19/2, 2020 at 15:43 Comment(0)
E
22

After months of on and off searching I managed to work it out, I was correct by using the File type, the reason it was returning empty on images that did exist is that I was missing the ever-special directive @fileByRelativePath.

For all those that are struggling with this, you must have an exported function called createSchemaCustomization in your gatsby-node.js, from here you must configure your frontmatter properties that you would like to provide the non-null values on.

exports.createSchemaCustomization = ({ actions, schema }) => {
    const { createTypes } = actions;

    const typeDefs = [
        `type MarkdownRemark implements Node {
            frontmatter: Frontmatter
        }`,
        `type Frontmatter @infer {
            about_hero_slides: [File!]! @fileByRelativePath,
            about_title: String,
            about_text: String,
            about_images: [File!]! @fileByRelativePath,
        }`,
    ];

    createTypes(typeDefs);
};

Once I added in @infer on the Frontmatter type and @fileByRelativePath to each File property it instantly resolved any images, and all images that didn't exist would simply return null instead of throwing an error!

Erewhile answered 6/4, 2020 at 13:47 Comment(1)
You sir, are a genius! 👏🏽 If only stack overflow had 'Buy a Beer' button.Barrelchested

© 2022 - 2024 — McMap. All rights reserved.