Gatsbyの@mosch/gatsby-source-githubでGitHubリポジトリの情報を取得する

Gatsbyを使いこなすには、data-sourceプラグインをどれだけ知っている / 使えるかが鍵かなと思います。ということで、今後お世話になりそうなsource pluginをいろいろ触ってみることにしました。 今回 […]

広告ここから
広告ここまで

目次

    Gatsbyを使いこなすには、data-sourceプラグインをどれだけ知っている / 使えるかが鍵かなと思います。ということで、今後お世話になりそうなsource pluginをいろいろ触ってみることにしました。

    今回はGitHubリポジトリのデータを取得する@mosch/gatsby-source-githubです。

    gatsby-source-github-repoも試そうとしたのですが、こちらはnpmから消えている様子です。

    install

    いつも通りnpmから落としてきましょう。

    $ yarn add gatsby-source-github-repo

    gatsby-config.jsで取得するリポジトリを指定

    リポジトリの指定はconfig側で行います。

        {
          resolve: `@mosch/gatsby-source-github`,
          options: {           
            repository: "react-sel",
            tree: true,
            releases: true,
            user: "hideokamoto",
          }
        }

    ドキュメントにはtokenの記載がありますが、なくてもpublicリポジトリはいけるみたいです。

    おそらくprivateリポジトリへのアクセスやAPIのスロットリング対策で必要なのではないかと思います。

    GraphQLクエリをつくる

    yarn developでGraphiQLを開いてクエリを作りましょう。このプラグインでは、「GitHubリポジトリのファイルを取得できるGitHubFiles」と「GitHubリポジトリで作成したRelease情報を取得できるGithubRelease」の2種類があります。

    Markdownファイル系のみ取得するクエリのサンプル

    query LIST_MARKDOWN_FILES {
       allGithubFile(filter: {path: {regex: "/.md$/"}}) {
         edges {
           node {
             repository
             content
             path
           }
         }
       }
     }

    Release情報を取得するクエリのサンプル

    query LIST_GH_RELEASES {
       allGithubRelease {
         edges {
           node {
             id
             name
             prerelease
             htmlUrl
             publishedAt
             body
             zipballUrl
           }
         }
       }
     }

    Reactで表示する

    Markdownファイルを表示するコンポーネントサンプル

    unified / remark-parse / remark-reactを追加して、Markdownファイルの内容をそのまま描画したコンポーネントです。

    import * as React from 'react'
    import {useStaticQuery, graphql, Link }  from 'gatsby'
    import * as unified from 'unified'
    import * as parse from 'remark-parse'
    const remark2react = require('remark-react')
    
    type AllGithubFileQuery = {
        allGithubFile: {
            edges: {
                node: {
                    repository: string;
                    content: string;
                    path: string;
                }
            }[]
        }
    }
    const useAllGithubFile = () => {
        const {
            allGithubFile: {
                edges
            }
        } = useStaticQuery<AllGithubFileQuery>(graphql`query LIST_MARKDOWN_FILES {
            allGithubFile(filter: {path: {regex: "/.md$/"}}) {
              edges {
                node {
                  repository
                  content
                  path
                }
              }
            }
          }`)
        return edges
    }
    
    export const ListGitHubDocumentFiles: React.FC = () => {
        const edges = useAllGithubFile()
        return (
            <>
                <h1>Documents</h1>
                <dl>
                    {edges.map(({node}) => (
                        <React.Fragment key={node.path}>
                            <dt>{node.path}</dt>
                            <dd>
                            {
                                unified()
                                    .use(parse)
                                    .use(remark2react)
                                    .processSync(node.content)
                                    .result
                            }
                            </dd>
                        </React.Fragment>
                    ))}
                </dl>
            </>
        )
    }
    

    描画するとこのようになります。

    実際に使う場合は、githubFileクエリの方で個別にuseStaticQueryする形の方が現実的かもしれません。

    Releaseを表示するコンポーネントサンプル

    続いてReleaseを表示するサンプルです。

    import * as React from 'react'
    import {useStaticQuery, graphql, Link }  from 'gatsby'
    import * as unified from 'unified'
    import * as parse from 'remark-parse'
    const remark2react = require('remark-react')
    
    type AllGithubReleaseQuery = {
        allGithubRelease: {
            edges: {
                node: {
                    id: string;
                    name: string;
                    prerelease: boolean;
                    htmlUrl: string;
                    publishedAt: string;
                    body: string;
                    zipballUrl: string;
                }
            }[]
        }
    }
    const useAllGithubRelease = () => {
        const {
            allGithubRelease: {
                edges
            }
        } = useStaticQuery<AllGithubReleaseQuery>(graphql`query LIST_RELEASES {
            allGithubRelease {
                edges {
                    node {
                        id
                        name
                        prerelease
                        htmlUrl
                        publishedAt
                        body
                        zipballUrl
                    }
                }
            }
          }`)
        return edges
    }
    
    export const ListGitHubReleases: React.FC = () => {
        const edges = useAllGithubRelease()
        return (
            <>
                <h1>Releases</h1>
                <pre><code>{JSON.stringify(edges,null,2)}</code></pre>
                <ul>
                    {edges.map(({node}) => (
                        <li key={node.id}>
                            <h2>{node.name}</h2>
                            <dl>
                                <dt>Published at</dt>
                                <dd>{new Date(node.publishedAt).toLocaleDateString()}</dd>
                                <dt>Download</dt>
                                <dd><a href={node.zipballUrl}>ZIP file</a></dd>
                            </dl>
                            {
                                unified()
                                    .use(parse)
                                    .use(remark2react)
                                    .processSync(node.body)
                                    .result
                            }
                        </li>
                    ))}
                </ul>
            </>
        )
    }

    zipballUrlのURLにそのままアクセスすると、ZIPファイルのダウンロードができますので、配布等にも使えそうです。

    使い所

    これもGitHubで公開・配布している系のツールサイトに使えそうです。

    ReadmeやChangelogなどのMarkdownで書かれがちなファイルの表示方法が以下の2パターン考えられます。

    1. allGihubFilesクエリのregexでまとめて取得し、gatsby-node.jsで動的にページ生成
    2. githubFilesクエリで表示したいファイルを個別指定し、pagesにファイル配置 + useStaticQueryで表示

    GitHub Actionsなどで、Releaseをpublishした際にNetlify / Vercel / AWS Amplify Consoleなどのビルドを実行させるように設定することで、ある程度GitHub側の更新にも自動で追従させられるのではないかと思います。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark