JAMstackなサイト制作__2_

話題のHeadlessCMS「microCMS」を試してみたwith Gatsby ~part2 Gatsbyを使ってViewを表示~

こんにちは。

りゅーそうです。

今回は前回に引き続き、JAMstackなサイトを作成していこうかと思います。今回は前回microCMSを使って作成したAPIを用いて実際にコンテンツをViewに反映してみたいと思います。

前回の記事はこちら。

前回作成したAPIはこちらになります。(多少前回の内容と異なっているかも知れません。)

NEWSとTAGSという名前のAPIを作成しました。

{
   "contents": [
       {
           "id": "news1",
           "createdAt": "2019-12-15T13:47:07.022Z",
           "updatedAt": "2019-12-17T13:46:49.971Z",
           "title": "2019年定期演奏会",
           "image": {
               "url": "https://images.microcms-assets.io/protected/ap-northeast-1:abe17a68-779f-4b0b-aac0-19290f80fbf4/service/guitar-club/media/icon.png"
           },
           "content": "<p>2019年定期演奏会<br>演奏会が行われました。<br>とても<strong>素晴らしい</strong>演奏会になりました。<br><u>感動しました</u><br><img src=\"https://images.microcms-assets.io/protected/ap-northeast-1:abe17a68-779f-4b0b-aac0-19290f80fbf4/service/guitar-club/media/icon.png?w=20&h=20\" alt><br></p>",
           "tags": [
               {
                   "id": "9A-g4g44V",
                   "createdAt": "2019-12-15T14:39:33.481Z",
                   "updatedAt": "2019-12-15T14:42:46.211Z",
                   "name": "Gitakura Info"
               }
           ],
           "date": "2019-12-09T11:15:00.000Z"
       },
       {
           "id": "news2",
           "createdAt": "2019-12-15T13:48:50.163Z",
           "updatedAt": "2019-12-17T13:20:32.034Z",
           "title": "OB/OGによるライブ開催決定!",
           "image": {
               "url": "https://images.microcms-assets.io/protected/ap-northeast-1:abe17a68-779f-4b0b-aac0-19290f80fbf4/service/guitar-club/media/audience-1835431_1920.jpg"
           },
           "content": "<p>ギタクラOB,OGによるライブを開催します。<br><br>場所時間は追って連絡します。</p>",
           "tags": [
               {
                   "id": "UbBlpn1O6",
                   "createdAt": "2019-12-15T14:40:06.380Z",
                   "updatedAt": "2019-12-15T14:42:26.541Z",
                   "name": "LIVE info"
               }
           ],
           "date": "2019-12-16T11:00:00.000Z"
       }
   ],
   "totalCount": 2,
   "offset": 0,
   "limit": 10
}

今回はこのデータを前提に話を進めていきます。


Gatsbyの環境を構築する


環境を構築というと語弊があるかも知れません。コマンドで一発です。

前回言った通り、gatsby-default-starter を使います。

ドキュメントにあるとおり、以下のコマンドでプロダクトを立ち上げます。

gatsby new [プロダクト名] https://github.com/gatsbyjs/gatsby-starter-default

gatsbyには様々なスターターがあるので、好みのものを使ってみてください。

作成されたファイルをみてみましょう。

スクリーンショット 2019-12-26 15.59.13

gatsby-node.js・・・動的なページを作成する際に設定するファイルです。Gatsbyでのライフサイクルの設定をこのファイルで行います。

gatsby-config.js・・・インストールしたプラグインの設定などを行います。少し中をのぞいてみましょう。

module.exports = {
 siteMetadata: {
   title: `Gatsby Default Starter`,
   description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
   author: `@gatsbyjs`,
 },
 plugins: [
   `gatsby-plugin-react-helmet`,
   {
     resolve: `gatsby-source-filesystem`,
     options: {
       name: `images`,
       path: `${__dirname}/src/images`,
     },
   },
   `gatsby-transformer-sharp`,
   `gatsby-plugin-sharp`,
   {
     resolve: `gatsby-plugin-manifest`,
     options: {
       name: `gatsby-starter-default`,
       short_name: `starter`,
       start_url: `/`,
       background_color: `#663399`,
       theme_color: `#663399`,
       display: `minimal-ui`,
       icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
     },
   },
   // this (optional) plugin enables Progressive Web App + Offline functionality
   // To learn more, visit: https://gatsby.dev/offline
   // `gatsby-plugin-offline`,
 ],
}

上記のデフォルトで入っている設定です。例えば、gatsby-plugin-react-helmetというメタタグなどを設定するプラグインの設定がされています。

plugins: [
   `gatsby-plugin-react-helmet`,
   {
     resolve: `gatsby-source-filesystem`,
     options: {
       name: `images`,
       path: `${__dirname}/src/images`,
     },
   },

plugins内に使いたいプラグインを書き、細かい設定を行うことができます(ちなみにgatsby-plugin-react-helmetはsrc/components内にあるseo.js内で使われています。その中の設定をいじれば、アイコンなどを変更することができます。gatsby-default-starterの便利さがわかるかと思います。)。

gatsby-browser.js/gatsby-ssr.js・・・今回は触りません。正直自分も設定方法がよくわかっていないのですが,ssrの設定の際などに使用するそうです。もし機会があれば解説したいと思います。

※記事を書きました(2020/6/2)

package.json・・・ご存知、npmを管理するファイルです。

.prettierrc・・・コードフォーマッターprettierの設定ファイルです。

src・・・実際に表示されるViewはここに書いていきます。中をみてみましょう。

スクリーンショット 2019-12-26 16.29.02

components・・・Reactのコンポーネントを書いていきます。

images・・・画像ファイルです。おっさんがいると思います。

pages・・・メインのコンテンツとなるファイルです。ここに作成したファイルはそのままルーティングになります。デフォルトでは上記の3つのファイルが作成されています。

実際に立ち上げてみましょう。

yarn develop

以下のようなページが表示されたかと思います。

スクリーンショット 2019-12-26 16.37.10

Go to page 2

スクリーンショット 2019-12-26 16.37.25

存在しない適当なURLを入力

スクリーンショット 2019-12-26 16.37.37

このように、pages内に作成したファイルがそのままページとして作成されます。とても簡単!

Gatsbyの基本は以上になります。


microCMSからデータを受け取る


では、前回作成したmicroCMSのデータを表示させてみましょう。

設定

まずは、GatsbyにもmicroCMS専用のプラグインが用意されているので、インストールしましょう。

yarn add gatsby-source-microcms

gatsby-config.jsに以下の設定をします。

plugins: [
   `gatsby-plugin-react-helmet`,
   {
     resolve: `gatsby-source-filesystem`,
     options: {
       name: `images`,
       path: `${__dirname}/src/images`,
     },
   },
     --- (中略) ---
   {
     resolve: "gatsby-source-microcms",
     options: {
       apiKey: "X-API-KEY",
       serviceId: "guitar-club",
       endpoint: "news",
     },
   },
 ],
}

optionsの設定の仕方は以下の通りです。

apikey・・・自身のプロダクトのAPI Keyを設定しましょう。API keyは以下の箇所のものを参照してください。

スクリーンショット 2019-12-26 16.55.35

serviceId・・・serviceのIDを設定します。トップページのこの辺↓に書いてあります。(左上のやつ)

スクリーンショット 2019-12-26 16.57.41

endpoint・・・実際のAPIのエンドポイントを記入。こちらで確認。

スクリーンショット 2019-12-26 16.59.43

※APIKEYはフロントエンド側に表示させるとセキュリティの問題があるので、dotenvなどを利用して、.envファイルを作成するなどして管理しましょう。詳しくは下記の記事をご覧ください。

設定は以上になります。


GraphQLでスキーマを作成


Gatsbyはデータの作成・転送はGraphQLを用いて行われます。とはいっても必要となる知識は対して多くはありません。実際にGraphQLのスキーマを設計してみましょう。

Gatsbyには簡単にAPI設定を試せる便利なツールがあります。

まずはローカル環境を立ち上げます。

yarn develop

そしたら、 http://localhost:8000/___graphql のリンクが表示されると思うので、クリックして表示させてください。

以下のような画面が表示されたかと思います。先ほど、gatsby-config.jsにmicroCMSの設定を加えたので、microCMSのデータを参照できるようになっているかと思います。

スクリーンショット 2019-12-26 17.12.45

左のqueryをクリックしながら、以下のようなスキーマを作成してみてください。microCMSで作成したコンテンツが表示されました!

スクリーンショット 2019-12-26 17.17.08

このようにクエリを叩いて試しながら、APIを作成していきます。次はこのクエリをGatsbyで実際に表示させてみましょう。


静的なページを作成する


src/pages/news.jsを作成しましょう。先ほどいったように自動的にページが作成されます。

以下のように入力します。

import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"


const NewsPage = ({ data }) => (
 <Layout>
   <SEO title="News" />

   {data.allMicrocmsNews.edges.map(edge => {
     const news = edge.node
     return (
       <React.Fragment key={news.id}>
         <div>
             <h2>{news.title}</h2>
           <div>
             {news.tags.map(tag => (
               <React.Fragment key={tag.id}>
                 <span>{tag.name}</span>
               </React.Fragment>
             ))}
           </div>
           <img
             src={news.image.url}
             width={160}
             height={110}
             alt="News投稿のイメージ画像"
           />
         </div>
       </React.Fragment>
     )
   })}
 </Layout>
)

export const query = graphql`
 {
   allMicrocmsNews(
     sort: { fields: [createdAt], order: DESC }
   ) {
     edges {
       node {
         id
         title
         date
         tags {
           id
           name
         }
         image {
           url
         }
         content
       }
     }
   }
 }
`

export default NewsPage

news.jsの解説

query部分のコードをみてみましょう。

export const query = graphql`
{
 allmicrocmsNews ....

の部分です。

ここには先ほど試したクエリを入力します。このように、GraphQLのクエリを使って、microCMSで作成したAPIを引っ張ってきてあげましょう。

このクエリはdataという名前のpropsとして、コンポーネントに渡されます。このクエリを参照しているコードをみてみましょう。

const NewsPage = ({ data }) => (
 <Layout>
   <SEO title="News" />

   {data.allMicrocmsNews.edges.map(edge => {
     const news = edge.node
     return (
       <React.Fragment key={news.id}>
         <div>
             <h2>{news.title}</h2>
           <div>
             {news.tags.map(tag => (
               <React.Fragment key={tag.id}>
                 <span>{tag.name}</span>
               </React.Fragment>
             ))}
           </div>
           <img
             src={news.image.url}
             width={160}
             height={110}
             alt="News投稿のイメージ画像"
           />
         </div>
       </React.Fragment>
     )
   })}
 </Layout>
)

このようにmapメソッドで繰り返し、データを取得します。今回はkeyを設定するために自動的に作成されるidを使用しました。

前回複数参照で取得したtagsもmapで繰り返し処理を行い取得します。

画像のサイズは今回は直接設定してしまいましたが、microCMSには画像のサイズなどを設定することもできます(Gatsbyの中でどのように使おうか模索しているところです。)。

詳しくはAPIリファレンスをご覧ください。

スクリーンショット 2019-12-27 16.52.22


以上のように、入力すると以下のような画面が表示されると思います(スタイルを多少当てているので、見た目が多少異なります。)。

スクリーンショット 2019-12-27 16.51.28

これで記事一覧ページのようなものを作成することができました!次は記事の詳細ページとリンクを作成してみましょう。


記事の詳細ページを作成する


では、作成していきます。このような動的なページを作成する際にはgatsby-node.jsファイルに記述していきます。

では、早速コードをみていきましょう。

gatsby-node.js

const path = require("path")

exports.createPages = async ({ graphql, actions }) => {
 const { createPage } = actions

 const result = await graphql(
   `
     {
       allMicrocmsNews {
         edges {
           node {
             id
           }
         }
       }
     }
   `
 )

 if (result.errors) {
   throw result.errors
 }

 result.data.allMicrocmsNews.edges.forEach(edge => {
   createPage({
     path: `/news/${edge.node.id}`,
     component: path.resolve(
       "./src/templates/news-post.js"
     ),
     context: {
       id: edge.node.id,
     },
   })
 })
}

どん!

動的なページを作成するためにGatsbyにはcreatePagesというAPIが用意されています。

使い方はリンクを参照してもらえればと思いますが、まずはgraphqlを引数にとるので、URLにしたい値を先ほどと同じように設定します。

続いて、actionsを引数にとることができるので、

result.data.allMicrocmsNews.edges.forEach(edge => {
   createPage({
     path: `/news/${edge.node.id}`,
     component: path.resolve(
       "./src/templates/news-post.js"
     ),
     context: {
       id: edge.node.id,
     },
   })
 })

このように設定します。

path・・・実際にURLとなります。microCMSのコンテンツの管理画面と同じURLを設定しましょう。

component・・・詳細ページのViewとなるファイルを設定します。こちらはこれから作成します。動的な詳細ページなどはtemplatesというフォルダに入れるのが慣習だそうです。

context・・・実際のコンテンツのURLを設定します。こちらのcontextに設定しておくことで、後ほどデータを引っ張る際にコンテンツ固有のidに紐づくデータを引っ張って表示させることができます。

上記の設定は公式を参照しました。一度確認しておきましょう。


では、詳細ページのテンプレートを作成していきます。

先ほど述べたとおり、src/templates/にnews-post.jsというファイルを作成しました。

src/templates/news-post.js

import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout/layout"

const NewsPost = props => {
 const post = props.data.microcmsNews
 return (
   <Layout>
     <div>
       <h2>{post.title}</h2>
       <div>
         <span>{post.tags.name}</span>
       </div>
       <img
         src={post.image.url}
         width={160}
         height={110}
         alt="News投稿のイメージ画像"
       />
       <p
         dangerouslySetInnerHTML={{
           __html: `${post.content}`,
         }}
       ></p>
     </div>
   </Layout>
 )
}

export default NewsPost

export const query = graphql`
 query($id: String!) {
   microcmsNews(id: { eq: $id }) {
     title
     date
     tags {
       name
     }
     image {
       url
     }
     content
   }
 }
`

ではコードをみていきましょう。

先ほど、gatsby-node.jsで設定したcontextを使用していますね。

ここの、、、

export const query = graphql`
 query($id: String!) {
   microcmsNews(id: { eq: $id }) {
     title
     date
     tags {
       name
     }
     image {
       url
     }
     content
   }
 }
`

この部分です。

microcmsNews(id: { eq: $id }) {

$idという部分で固有のidを引っ張ることができています。また、今回は個別の記事を表示させたいので、microcmsNewsを使用していることに注意してください(allmicrocmsNewsではないということです。記事一覧ページを作成した時のようにローカル環境で、データ表示を試して見ると良いでしょう。)。

あとは記事一覧ページを作成した時とほとんど同じなのですが、一点だけ注意があります。microCMSのリッチエディタで作成したコンテンツはHTML形式でデータを返すので、

参考:contentの部分です。

{
   "id": "news2",
   "createdAt": "2019-12-15T13:48:50.163Z",
   "updatedAt": "2019-12-17T13:20:32.034Z",
   "title": "OB/OGによるライブ開催決定!",
   "image": {
       "url": "https://images.microcms-assets.io/protected/ap-northeast-1:abe17a68-779f-4b0b-aac0-19290f80fbf4/service/guitar-club/media/audience-1835431_1920.jpg"
   },
   "content": "<p>ギタクラOB,OGによるライブを開催します。<br><br>場所時間は追って連絡します。</p>",

これを変換して表示させて上げる必要があります。そこで使っているのがReactのdangerouslySetInnerHTMLメソッドです。

その名のとおり、使用には注意してください。上記のように使用すれば問題はありません。


最後に記事一覧ページから詳細ページにリンクできるようにしておきましょう。

src/pages/news.js

import React from "react"
//Linkをインポートする
import { graphql, Link } from "gatsby"

//------略------

const NewsPage = ({ data }) => (
 <Layout>
   <SEO title="News" />
   
   {data.allMicrocmsNews.edges.map(edge => {

//-------略--------
//リンクを設定する。先ほど詳細ページのURLのpathに使用したidを利用
           <Link to={`/news/${news.id}`}>
             <h2>{news.title}</h2>
           </Link>
     
    
     )
   })}
 </Layout>
)

//--------略--------

export default NewsPage

これで完成です!リンクから個別ページが表示できたでしょうか?

スクリーンショット 2019-12-27 22.59.48


課題


詳細ページの実際のURL

http://localhost:8000/news/24fafe3f-a06f-5e32-9b40-d6ae03274545

わかりやすいURLを設定したい。

スクリーンショット 2019-12-27 23.02.41

microCMSでは上のように固有のcontentIdを設定できる。それをgraphQLで引っ張る。

スクリーンショット 2019-12-27 23.04.38

表示できた。

ただ、gatsby-node.jsでpathに設定してもうまくいかなかった。うまくできたらまた共有したいと思います。


まとめ


以上で、一応ブログやコンテンツ配信などの基本的な部分は再現できたのかと思います。あとは、ぜひスタイルなど自分の好きなようにカスタマイズしてみてください!


自分もこれから色々と試してみたいと思っているので、よろしくお願いします。


※ 現在以下URLのブログにて情報発信を行なっています!ぜひ、ご覧ください!

 TypeScriptでGatsby×microCMSを動かす記事​


サポートくださると励みになるので、よろしくお願い致します!サポートは全てプログラミングの勉強に使わせていただきます。またアウトプットして還元します^_^