GatsbyJSでまだ流し込むデータが無いページテンプレートを作る際に気をつけること


こんにちは、Gaji-Labo アシスタントエンジニアの石垣です。

今回は、React 用静的サイトジェネレーターの GatsbyJS で静的サイトを制作しているなかで、まだ流し込むデータが存在しないページテンプレートを作った際の GraphQL の書き方で気をつけることについてまとめたいと思います。

発生した問題

Gaji-Labo のコーポレートサイトを GatsbyJS を制作している際に、「まだ流し込むデータは存在しないが、データを追加した時にすぐにページが生成できるように前もってテンプレートを用意したい」ということがありました。

既にページの構成が決まっており、どのようなデータが渡ってくるかも分かっていたので、 src ディレクトリ内に追加した Markdown ファイルから GraphQL でデータを取得することを想定して、以下のようなテンプレートを用意しました。

import React from 'react';
import { graphql } from 'gatsby';

const Example = (props) => {
  const { data } = props;
  const { markdownRemark: post } = data;

  return (
    <>
      <h1>{post.frontmatter.title}</h1>
      <p>
        {post.frontmatter.description}
      </p>
      <div
        dangerouslySetInnerHTML={{ __html: post.frontmatter.bodyBeforeImage }}
      />
      <img
        src={post.frontmatter.image}
        alt={post.frontmatter.imageAlt}
      />
      <div
        dangerouslySetInnerHTML={{ __html: post.frontmatter.bodyAfterImage }}
      />
    </>
  );
};

export default Example;

export const pageQuery = graphql`
  query ExampleByID($id: String!) {
    markdownRemark(id: { eq: $id }) {
      frontmatter {
        title
        description
        bodyBeforeImage
        image
        imageAlt
        bodyAfterImage
      }
    }
  }
`;

以下のような Markdown ファイルからデータを取得する想定で、実際にサンプルの Markdown ファイルを追加してページが生成されることも確認できました。

---
type: example
date: 2020-07-30
slug: 'example-001'
title: ダミータイトル
description: ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキスト
bodyBeforeImage: ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキスト
image: example.png
imageAlt: 'ダミーalt'
bodyAfterImage: ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキスト
---

しかし、本番リリースのためにサンプルの Markdown ファイルを削除すると、 下記のエラーが出てビルドが失敗するようになってしまいました。

ERROR #85923  GRAPHQL

There was an error in your GraphQL query:

Cannot query field "bodyBeforeImage" on type "MarkdownRemarkFrontmatter".

If you don't expect "bodyBeforeImage" to exist on the type "MarkdownRemarkFrontmatter" it is most likely a typo.
However, if you expect "bodyBeforeImage" to exist there are a couple of solutions to common problems:

- If you added a new data source and/or changed something inside gatsby-node.js/gatsby-config.js, please try a restart of your development server
- The field might be accessible in another subfield, please try your query in GraphiQL and use the GraphiQL explorer to see which fields you can query and what shape they have
- You want to optionally use your field "bodyBeforeImage" and right now it is not used anywhere. Therefore Gatsby can't infer the type and add it to the GraphQL schema. A quick fix is to add a least one entry with that field ("dummy content")

It is recommended to explicitly type your GraphQL schema if you want to use optional fields. This way you don't have to add the mentioned "dummy content". Visit our docs to learn how you can define the schema for "MarkdownRemarkFrontmatter":
https://www.gatsbyjs.org/docs/schema-customization/#creating-type-definitions

File: src/templates/example.tsx:36:9

failed extract queries from components - 0.190s

解決のために試したこと

エラー文を読むと、 MarkdownRemarkFrontmatter に bodyBeforeImage が存在していないためにエラーが発生していることが分かりました。

GraphQL では、取得しようとしたフィールドが存在しない時に無視することはせず、前述のようなエラーを返します。

エラー文で提案されているようにダミーファイルを追加しておくことを検討しましたが、本番環境にもダミーのページが生成されてしまうため現実的ではありませんでした。

最終的に、以下のように現状存在していないフィールドをコメントアウトして対応しました。

export const pageQuery = graphql`
  query ExampleByID($id: String!) {
    markdownRemark(id: { eq: $id }) {
      frontmatter {
##      title
##      description
##      bodyBeforeImage
##      image
##      imageAlt
##      bodyAfterImage
      }
    }
  }
`;

コメントアウトすることでエラーは発生しなくなり、ビルドできるようになりました。

まとめ

今回はGatsbyJS で静的サイトを制作する際に、まだ流し込むデータが存在しないテンプレートを作った時に GraphQL の記述で気をつけることについてまとめました。

GraphQL についてはまだ理解が浅いので、問題に遭遇しながら知見を深めている状態です。この問題に対してよりよい知見があれば、教えていただけると大変ありがたいです!

GatsbyJS を使用していて同じ問題に遭遇した際の参考にしていただけたらと思います。

Gaji-Laboでは、JavaScriptフレームワーク経験が豊富なパートナーさんを募集しています

Gaji-Laboでは、開発チームの一員としてプロジェクトに一緒に取り組んでくれる業務委託のパートナーさんを募集しています。

現在は特にJavaScriptフレームワーク実践と業務経験が豊富なWebフロントエンドエンジニアを必要としています。React + TypeScript、Vue.js、Next.js、Nuxt.js など、あなたの得意なフレームワークを教えて下さい!

パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでのリモート面談からはじめましょう。ぜひお気軽にお問い合わせください!

お問い合わせしてみる!

投稿者 Ishigaki Shotaro

未経験から Gaji-Labo に入社。現在は React/TypeScript/Next.js の案件で MUI を使ったコンポーネント組み込みを担当。プロジェクトチームのリードとして共に組み込み作業をしているメンバーの進行管理も行っています。休日はだいたい家で音楽を聴いており、たまにライブに出かけています。