How to create schema customization to use optional field “featureImage” from gatsby blog

I’m making a Gatsby blog as a side project.

I want to use the “featureImage” optional field in mdx frontmatter.

I tried to refer to the https://www.gatsbyjs.com/docs/reference/graphql-data-layer/schema-customization#creating-type-definitions document according to the error message, but it was difficult to understand.

This is part of my code.

index.js

import React, { useEffect } from "react";
import { graphql } from "gatsby";
import { App, ContentCard, TagsNavi, User } from "../components";
import { ContentWrapper } from "../elements";
import { useDispatch, useTag } from "../store/StoreContext";
import { ALL, SET_TAG, TAG } from "../constants";

const IndexPage = ({ location, data }) => {
  const {
    allMdx: { edges },
  } = data;

  const tag = useTag();
  const dispatch = useDispatch();

  useEffect(() => {
    const tagName = new URLSearchParams(location.search).get(TAG);
    dispatch({ type: SET_TAG, tag: tagName || ALL });
  }, [dispatch, location.search]);

  return (
    <App title="Home">
      <div>
        <ContentWrapper>
          <User />
          <TagsNavi />
          {edges
            .filter(
              (edge) => edge.node.frontmatter.tags.includes(tag) || tag === ALL
            )
            .map((edge) => {
              const { node } = edge;
              return <ContentCard key={node.slug} {...node} />;
            })}
        </ContentWrapper>
      </div>
    </App>
  );
};

export default IndexPage;

export const pageQuery = graphql`
  query AllPostsQuery {
    allMdx(sort: { fields: frontmatter___date, order: DESC }) {
      edges {
        node {
          slug
          excerpt(pruneLength: 140, truncate: true)
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            tags
            title
            featureImage {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
      }
    }
  }
`;

gatsby-node.js

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions;
  const typeDefs = `
    type MdxFrontmatter implements Node {
      featureImage: File
    }
  `;
  createTypes(typeDefs);
};

I tried this and it works when featureImage is not present. But if I have featureImage it doesn’t work.

How can I create the functionality I want? Please help me.

I’m not good at English, so I use a translator so my words may be a little weird. Sorry.


The Codesandbox address is here. https://codesandbox.io/s/gatsby-starter-ki-demo-8fyty?file=/gatsby-node.js

When tested locally, GraphiQL playground output: “Cannot read property ‘contentDigest’ of undefined” terminal message: ERROR getNodeAndSavePathDependency failed for node id: undefined as it was not found in cache

warn You can’t use childImageSharp together with undefined.undefined — use publicURL instead. The childImageSharp portion of the query in this file will return null: undefined

Browser console: Warning: Failed prop type: The prop image is marked as required in GatsbyImage, but its value is undefined.

[gatsby-plugin-image] Missing image prop

Answer

You may find this GitHub thread insightful. Following it, try using:

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

  createTypes(`
    type Mdx implements Node {
      frontmatter: MdxFrontmatter!
    }
    type MdxFrontmatter {
      featuredImage: File @fileByRelativePath
    }
  `)
}

The problem I assume in your implementation is that there were no internal nodes for Gatsby to treat your image so the resolver can’t find the path to create childImageSharp, etc. That’s why the output was undefined.

Other useful threads:


Browser console: Warning: Failed prop type: The prop image is marked as required in GatsbyImage, but its value is undefined.

This one is because you are trying to render GatsbyImage whether exists or not, so you are not passing any image prop. You’ve not shared the logic in the component but add a simple ternary condition like:

{data.someNode.featuredImage && <GatsbyImage image={data.someNode.featuredImage} /> }

P.S: it’s a pity the CodeSandbox issue and thanks for trying it