このサイトは Gatsby + Netlify + Gatsby で運用していて、開発体験もページ遷移速度も SEO も優れていて、非常に気に入っているのですが、今日そこそこハマりその解決策がわかったので、メモします。

Contentful から取得した content の childMarkdownRemark が存在しない場合のエラー処理を追加すること

Contentful にマークダウンでブログコンテンツを保持して、変更があった場合には Netlify に hook をして、Netlify で運用している Gatsby が静的サイトをビルドし直す。これが Contentful + Netlify + Gatsby を連携している場合の基本的な運用ですが、稀に childMarkdownRemark もしくは content がない記事が発生する場合があります。その場合は当然ですが null の場合のハンドリングをします。

具体的には以下のような箇所でおきます。

childMarkdownRemark から記事を作る部分
<div
  className="post-content"
  dangerouslySetInnerHTML={{
    __html: post.content.childMarkdownRemark.html,
  }}
/>

私の場合 childMarkdownRemark is null というエラーが出ていました。

Contentful から取得してきたデータのうち、childMarkdownRemark.html を Gatsby でレンダリングする際に、これが null のためにエラーが出ているわけです。

null の場合だけ childMarkdownRemark.html を使わないように適当な内容を返せばいいです。

以下実際のこのブログのソースです。

対策
import React from 'react'
import { graphql, Link } from 'gatsby'
import Layout from '../components/layout'
import SwitchEnglish from 'src/components/SwitchEnglish'

export default ({ data }) => {
  const post = data.contentfulBlogPost
  const translatedMode = post.tags.some(
    o => o === 'Translated-Text' || o === 'Translated Text'
  )

  const { content } = post // この値が null になることがわかったので
  if(!content) {
    console.log(post)
    return <div>Error</div> // 例外の場合は適当なものを返す
  }
  
  return (
    <Layout description={post.description} title={post.title}>
      <div className="post">
        <div className="title-wrapper">
          <h1 className="post-title">{post.title}</h1>
          <a
            target="_blank"
            rel="noopener noreferrer"
            href={`https://twitter.com/intent/tweet?text=${
              post.title
            }%0a&hashtags=UncleJavascript&url=https://uncle-javascript.com/${
              post.slug
            }/&via=better_than_i_w`}
            className="tweet"
          >
            Tweet
          </a>
        </div>
        <div className="post-ui-wrapper">
          <div className="post-ui-item-wrapper">
            {post.tags.map(o => (
              <Link key={o} to={o} className="post-ui-item">{o}</Link>
            ))}
          </div>
          <SwitchEnglish translatedMode={translatedMode} />
        </div>
        <div
          className="post-content"
          dangerouslySetInnerHTML={{
            __html: post.content.childMarkdownRemark.html,
          }}
        />
      </div>
    </Layout>
  )
}

export const query = graphql`
  query($slug: String!) {
    contentfulBlogPost(slug: { eq: $slug }) {
      id
      title
      description
      slug
      tags
      content {
        childMarkdownRemark {
          html
        }
        id
        content
      }
      createdAt
    }
  }
`

いつおきるのか

完全に原因は特定できていないのですが、おそらく Contentful の記事更新の hook で netlify が再ビルドをしてエラーが出現した場合で、かつ同じタイミングで記事を増やした時ではないかなと思っています。

ただし、一旦 netlify でのビルドが正常化された後には、content が null になる記事は存在しなくなりました。本当に一時的に起こるようです。

以下根拠のない推測ですが、Contentful の記事更新 => hook => Netlify の通知だけではなく、Netlify のビルド終了 => Contentful の通知もあって、それによって Build する内容を規定しているのではないでしょうか。

何にせよ、エラーがおきている箇所で値が存在するかどうかをチェックして、例外処理するという一般的な開発フローで解決できてよかったです。