createPagesの実装

はじめに

createPages の実装を行います。
この関数は、 Gatsby から呼ばれます。
前回作成した slug を元にページを追加します。

手順

主な手順としては、以下になります。

  1. GraphQL でマークダウンコンテンツを取得
  2. 取得した各要素に対してページを追加

編集するファイルは以下です。

./src/gatsby-helpers/createPages.ts

createPagesの実装

GraphQLでマークダウンコンテンツを取得

GraphQL を用いて Markdown コンテンツを取得します。 各 Markdown において、必要なのは slug です。 ということで、クエリ文字列は以下になります。

  {
    allMarkdownRemark {
      edges {
        node {
          fields {            slug          }        }
      }
    }
  }

ここでハイライトされている部分が、onCreateNode で追加した部分になります。

ページの追加

型の定義

関数の引数の型を Gatsby の型定義ファイルを参考にして以下の様に定義します。

interface CreatePagesArgs {
  graphql: Function;
  actions: Actions;
}

結果の値の型を GraphQL を参考にして以下の様に定義します。

interface Post {
  node: {
    fields: {
      slug: string;
    }
  }
}

interface ResultType {
  data: {
    allMarkdownRemark: {
      edges: Post[];
    }
  };
  errors?: any;
}

createPageによるページの追加

createPageを呼ぶ際にページオブジェクトの以下の3つの値を指定します。

  • path
  • component
  • context
path

'/' で始まるページのURLを指定します。 ここで slug を使用します。

component

ページを構成するためのReactコンポーネントを指定します。

const blogPostTemplate = resolve('./src/templates/BlogPost.tsx');

ここファイルの説明は次回の記事にて行います。

context

ここで指定する値は、ページ作成の際に this.props.pageContext でアクセスできます。 また、ページクエリを使用する際のGraphQLのクエリ引数として使用できます。 例えば、context に以下の様に指定したとします。

{
  foo: 'bar',
}

ページ表示用のコンポーネント側では、以下の様に呼び出すことができ $foo には 'bar' が指定されます。

export const query = graphql`
    query($foo: String!) {        markdownRemark(fields: { baz: { eq: $foo } }) {            ...
        }
    }
`;

上記の例では、fieldsbaz'bar' であるページが取得されます。

関数の呼び出し

実際の呼び出しは以下になります。

const posts = result.data.allMarkdownRemark.edges;
posts.map((post: Post) => {
  const slug = post.node.fields.slug;

  createPage({
    path: `/posts${slug}`,
    component: blogPostTemplate,
    context: {
      slug: slug,
    },
  });
});

ここで posts の型は Post[] であり、mapを使用して各 Post に対して createPage を呼ぶ構図になっています。

コード全体

コード全体は以下の様になりました。

// ./src/gatsby-helpers/createPages.ts
import { resolve } from 'path';
import { Actions } from 'gatsby';

interface CreatePagesArgs {
  graphql: Function;
  actions: Actions;
}

interface Post {
  node: {
    fields: {
      slug: string;
    }
  }
}

interface ResultType {
  data: {
    allMarkdownRemark: {
      edges: Post[];
    }
  };
  errors?: any;
}

export const createPages = ({ graphql, actions }: CreatePagesArgs): void => {

  const { createPage } = actions;

  return graphql(`
    {
      allMarkdownRemark(
        sort: { fields: [frontmatter___date], order: ASC }
      ) {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `).then((result: ResultType) => {
    if (result.errors) {
      throw result.errors;
    }

    const blogPostTemplate = resolve('./src/templates/BlogPost.tsx');

    const posts = result.data.allMarkdownRemark.edges;

    posts.map((post: Post) => {
      const slug = post.node.fields.slug;

      createPage({
        path: `/posts${slug}`,
        component: blogPostTemplate,
        context: {
          slug: slug,
        },
      });
    });
  });
};

おわりに

ここまでで、Markdown ファイルをページに追加する処理は完成しました。
次回は、createPage で指定した component の中身について記述します。