dotgirl.net
Gatsby でも公開非公開設定を制御したい

February 14, 2020

Gatsby でもその他のブログツールのように、公開・公開設定を制御したい気持ちになりました。

公開設定の理想と現実

Gatsby で Markdown の記事などから GraphQL で公開データを取得してきたいとします。 ビルド環境に関係がない場合 GraphQL では filter を使って以下のように取得できます。

exports.createPages = async ({ graphql, actions }) => {
  ...
  const result = await graphql(`
    {
      allMarkdownRemark(
        sort: { fields: [frontmatter___date], order: DESC }
        limit: 2000
        filter: { frontmatter: { published: { eq: true } } }
      ) {
        edges {
          node {
            fields {
              slug
            }
            frontmatter {
              title
              date(formatString: "MMMM DD, YYYY")
              description
              tags
            }
          }
        }
      }
    }
  `)
  ...
}

ここでは、markdown で書いた記事の frontmatter 部分に published が定義されており、 truefalse が入ることを想定しています。

filter で frontmatter の published が true に一致する場合の記事情報を取得する一番てっとりやすそうな方法です。

さて、ここで開発環境のときにのみ、 published: false な記事をサイトに表示しておきたいとします。安易に考えると以下のように書きたくなります。 以下のコードは String interpolation is not allowed in graphql tag と言われて動きません。

exports.createPages = async ({ graphql, actions }) => {
  ...
  const result = await graphql(`
    {
      allMarkdownRemark(
        sort: { fields: [frontmatter___date], order: DESC }
        limit: 2000
        filter: ${process.env.NODE_ENV === 'production' ? { frontmatter: { published: { eq: true } } } : ''}
      ) {
        edges {
          node {
            fields {
              slug
            }
            frontmatter {
              title
              date(formatString: "MMMM DD, YYYY")
              description
              tags
            }
          }
        }
      }
    }
  `)
  ...
}

どうやらタグ付きテンプレートリテラルの中で文字展開はできないようなので、その他の方法で実装するしかなさそうです。

こんな感じで nodes 配列を渡して published なものだけ取り出していきます。

const getOnlyPublished = edges =>
  edges.filter(({ node: post }) => post.frontmatter.published)

process.env.NODE_ENV === 'production' のときだけ上記関数を適用します。 このとき、GraphQL のクエリに published を入れ忘れると、公開されてしまうので注意です。

...
  const result = await graphql(`
    {
      allMarkdownRemark(
        sort: { fields: [frontmatter___date], order: DESC }
        limit: 2000
      ) {
        edges {
          node {
            fields {
              slug
            }
            frontmatter {
              title
              date(formatString: "MMMM DD, YYYY")
              description
              published
              tags
            }
          }
        }
      }
    }
  `)

const allPosts = result.data.allMarkdownRemark.edges
const posts =
  process.env.NODE_ENV === 'production'
    ? getOnlyPublished(allPosts)
    : allPosts
...

いろんな starter もみてみましたが同じような実装でしたので、とりあえずこの方法で🥺。

Weekly number of page views since last build: 🥰

0hit
    © 2025, Built with Gatsby