Gatsby の createPages がキャッシュされてしまい、次の記事へのリンク等が更新されない問題に対処するワークアラウンド

3 min read読了の目安(約2700字

問題点

最近 Gatsby 3.1.0 でサイトを構築し、GitHub のリポジトリと連携して Vercel でホスティングしてブログを公開したのですが、Gatsby でブログを構築する際、各記事のフッターに「次へ」や「前へ」などのリンクを貼りたいことがあります。これらは gatsby-starter-blog などのスターターにも含まれており、gatsby-node.js に定義された createPages によってビルド時に生成されます。

本来であれば、リンクの生成は新規記事の追加や過去記事の削除によって変化し、ビルド時に更新されることが期待されるでしょう。しかし、新規記事を追加した際に、ひとつ前の記事から次へのリンクが追加されない現象がたびたび発生していました。

当初は Vercel 側のキャッシュを疑っていたのですが、Gatsby の Issue #26520 にて全く同様の事象が報告されており、原因はタイトルにもあるように Gatsby 本体の createPages のキャッシュによるものでした。この問題は本記事執筆時点でも修正されていないのですが、ワークアラウンドが記載されていたためこちらで紹介します。

ワークアラウンド

pieh 氏という方がこちらで公開されているので、分かる方はご自分でご確認ください。一応私がやったことをまとめます(ほぼ同じですが……)。

gatsby-node.js にワークアラウンド用の関数を追加

gatsby-node.js に以下を追記します。コメントも含めて全て pieh 氏のものと同じです。

gatsby-node.js
exports.createResolvers = ({ createResolvers }) => {
  createResolvers({
    Query: {
      contextChangeNotInvalidingQueryWorkaround: {
        type: `JSON`, // type actually doesn't matter - we will return/resolve `null` anyway
        args: {
          path: {
            type: `String!`,
          },
        },
        resolve: async (_source, args, context) => {
          // Lookup SitePage node for current page.
          // This will register SitePage node as dependency of the query.
          // Changing context does change SitePage, so it will invalidate
          // query result properly.
          await context.nodeModel.runQuery({
            query: {
              filter: {
                path: { eq: args.path },
              },
            },
            type: `SitePage`,
            firstOnly: true,
          })

          return null
        },
      },
    },
  })
}

テンプレートの graphql クエリにワークアラウンドを追加

createPages で呼んでいる各テンプレートのクエリに$path: String! に追加し、併せて上記のワークアラウンド用関数を呼び出します。ここでは私のコードから引用しているため関係のないものも含まれていますが、適宜読み替えてください。

src/templates/blog-post.js
export const pageQuery = graphql`
  // *追加* query に $path: String! を追加
  query($slug: String!, $path: String!) {
    site {
      siteMetadata {
        title
        author
      }
    }
    mdx(fields: { slug: { eq: $slug } }) {
      id
      excerpt(pruneLength: 160)
      frontmatter {
        title
        date(formatString: "YYYY/MM/DD")
        tags
      }
      body
    }
    // *追加* ワークアラウンド用関数呼び出しを追加
    _: contextChangeNotInvalidingQueryWorkaround(path: $path)
  }
`

「前へ」「次へ」のリンクだけでなく、月別のアーカイブページなども createPages からテンプレートを呼び出して生成している場合は、それぞれのテンプレート全てに上記の対応が必要です。

その他

ワークアラウンドの適用で、私のサイトではリンク等が適切に更新されることを確認しています。原因は詳しく追ってないので、詳細を知りたい方は上述の Issue から関連する PR を辿っていただければと思います。