Cloudflare Pages x microCMS x GatsbyJSでブログを作ってみる
知り合いが「Wordpressでブログ云々...」と話しているのを聞いて、ふと「いまどきブログを作るなら、どんな構成がいいんだろう?」と思い、調べて作ってみることにしました。
CMS
今回は日本語対応でAPIベースのmicroCMSにすることにしました。
最初はホスティングサービスであるNetlifyが提供しているNetlify CMSが一番簡単にすむかなと思ったのですが、エディタの日本語入力が怪しいという情報が散見されたのと、ホスティングサービスとしてもVercelやCloudflare Pagesの方がパフォーマンスがよさそうだったのでやめました。
他には、最もメジャーで機能が豊富そうなContentfulと、標準でGraphCMSが気になりました。
本格的にブログを運用する場合は、機能面でもいろいろと違うみたいなので、CMSだけ触ってみて比較してみた方が良さそうですね。
ホスティングサービス
Zennの開発者でもあるcatnoseさんが、こちらの記事でVercel, Netlify, Cloudflare Pagesを詳細に比較されています。
他の方も書かれていましたが、Netlifyはページの表示速度が体感でわかるくらい遅いというのが大きなマイナスポイントですね。
パフォーマンス的にはVercelとCloudflare Pagesが並ぶところですが、Vercelは無料プランだと商用利用が許可されておらず、広告を貼るだけでもダメなようだったので、今回はCloudflare Pagesを選択しました。
サイト数・Bandwidth・リクエスト数のすべてが無制限ということで、最強ですねw
フレームワーク
Next.jsかGatsbyJSかで迷い、GatsbyJSにしました。
GatsbyJSは使用した経験が無かったのですが、テンプレートやプラグインというGatsbyJS専用のnpmモジュール群が充実していて、「静的ページをReactベースでサクッと作るならGatsbyJS」という印象を持ったので、GatsbyJSを選択しました(どうでもいいけど、「ギャッツビー」って音がカッコイイw)
実際触ってみると、GraphQLインターフェースが徹底されていて、例えば、設定ファイルに記載したメタデータやプラグインが提供するデータにGraphQLでアクセスすることができます。
microCMSの公式プラグインも用意されていて、microCMS自体はREST APIを提供していますが、プラグインにAPIキーなどの情報を設定することで、GraphQLでデータにアクセスできるようになります。
GatsbyJSの仕組みに関しては、こちらのブログで連載されているGatybyJS関係の記事が素晴らしくわかりやすかったので、おすすめです。
作ってみる
ローカルで表示する
主な参考はこちら。
使用するStarterはこちら。
npx gatsby new gatsby-microcms-starter-blog https://github.com/gatsbyjs/gatsby-starter-blog
...
Your new Gatsby site has been successfully bootstrapped. Start developing it by running:
cd gatsby-microcms-starter-blog
gatsby develop
ローカルで表示してみます。
cd gatsby-microcms-starter-blog
gatsby develop
Starterがローカルで表示されました。
APIの作成
次に、microCMSでAPIを作成していきます。
新規登録から進んでいくと、「サービスの作成(の情報を入力)」という画面が表示されます。
サービスというのは、テキストや画像など任意の情報を提供するAPIをまとめたものです。
ここで料金プランを確認して驚いたのですが、無料プランであるHobbyでは、1サービスにつきAPIは最大3個までという制限はあるものの、サービスの数に関しては制限がないんですね。
すでにサービスを1つ作っている私のアカウントでも試してみたら、問題なくサービスがもう一つ作れるようでした。
サービスIDは管理画面やAPIのエンドポイントのサブドメインになります。
次にAPIの情報を入力する画面が出てくるのでこちらも入力していきます。
APIの型を選択します。
ブログの記事など、複数個データを提供するものはリスト型、ブログのタイトルや設定情報など、単体のデータを提供するものはオブジェクト型を選択します。
今回はブログ記事なので、リスト型を選択しました。
次にAPIスキーマを定義する画面が表示されます。
ここでは、APIが提供するデータを設定していきます。
こちらはAPIを作成後、「API設定」→「APIスキーマ」から表示したAPIの編集画面ですが、いつでもスキーマを編集することができます。
APIを作成すると、「コンテンツがありません」と表示されるので、設定したスキーマに従ってデータを入力し、コンテンツを作成します。
これでAPIの作成は完了です。
上のコンテンツ一覧画面の右上ある「APIプレビュー」をクリックすると、APIにアクセスするための情報が確認できます。
X-MICROCMS-API-KEY、サービスID(.microcms
の前のサブドメインの値)、エンドポイント(blogなど)をこの後で環境変数に設定します。
microCMSからデータを取得する
ローカルで作成したGatsbyJSのStarterで、microCMSで作成したAPIからデータを取得できるようにしていきます。
microCMS専用のプラグインであるgatsby-source-microcms
と、環境変数を設定するためにdotenv
をインストールします。
npm install gatsby-source-microcms dotenv
ルートディレクトリに.env
を作成して、先ほど確認したAPIにアクセスするための情報を入力します。
MICROCMS_API_KEY={X-MICROCMS-API-KEYの値}
MICROCMS_SERVICE_ID={Service ID}
MICROCMS_ENDPOINT={API Endpoint}
次に、gatby-config.js
でdotenv
を有効にして、プラグインに関する設定を記載します。
require("dotenv").config()
module.exports = {
...
plugins: [
...,
// For microCMS
{
resolve: "gatsby-source-microcms",
options: {
apiKey: process.env.MICROCMS_API_KEY,
serviceId: process.env.MICROCMS_SERVICE_ID,
apis: [
{
endpoint: process.env.MICROCMS_ENDPOINT,
format: "list",
},
],
},
},
]
}
gatsby develop
を再度実行して、http://localhost:8000/___graphql
をブラウザで開いてPlaygroundを確認すると、
クエリルート一覧にallMicrocmsBlog
とmicrocmsBlog
が追加されているのがわかります。
Blog
の部分は先ほどgatsby-config.js
で設定したendpoint
の値の先頭を大文字にしたものです。
ちなみに、format: "object"
としてしまうと、nodeの型が変わってしまうため、この後で、nodes { blogId }
などとクエリしようとすると、Cannot query field "blogId" on type "MicrocmsBlog".
などとエラーが出てしまいます(ハマりました...)
次に、一覧画面用のページファイルであるsrc/pages/index.js
を修正して、記事一覧を表示できるようにします。
index.js
import * as React from "react"
import { Link, graphql } from "gatsby"
import Bio from "../components/bio"
import Layout from "../components/layout"
import Seo from "../components/seo"
const BlogIndex = ({ data, location }) => {
const siteTitle = data.site.siteMetadata?.title || `Title`
const posts = data.allMicrocmsBlog.nodes
if (posts.length === 0) {
return (
<Layout location={location} title={siteTitle}>
<Seo title="All posts" />
<Bio />
<p>
No blog posts found. Add markdown posts to "content/blog" (or the
directory you specified for the "gatsby-source-filesystem" plugin in
gatsby-config.js).
</p>
</Layout>
)
}
return (
<Layout location={location} title={siteTitle}>
<Seo title="All posts" />
<Bio />
<ol style={{ listStyle: `none` }}>
{posts.map(post => {
const title = post.title || "Title"
return (
<li key={post.blogId}>
<article
className="post-list-item"
itemScope
itemType="http://schema.org/Article"
>
<header>
<h2>
<Link to={post.blogId} itemProp="url">
<span itemProp="headline">{title}</span>
</Link>
</h2>
<small>{post.createdAt}</small>
</header>
<section>
<p
dangerouslySetInnerHTML={{
__html: post.description || "default body",
}}
itemProp="description"
/>
</section>
</article>
</li>
)
})}
</ol>
</Layout>
)
}
export default BlogIndex
export const pageQuery = graphql`
query {
site {
siteMetadata {
title
}
}
allMicrocmsBlog(sort: { fields: [createdAt], order: DESC }) {
nodes {
blogId
title
description
createdAt
}
}
}
`
http://localhost:8000/
にアクセスして確認してみると、
データが取得できているのがわかります。
続いて、gatsby-node.js
を編集します。
gatsby-node.js
に記載したコードはビルド時に実行され、たとえば、createPage
でURLのパスやコンポーネント、渡すデータなどを設定してページを作ることができます。
gatsby-node.js
...
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
// Define a template for blog post
const blogPost = path.resolve(./src/templates/blog-post.js
)
// Get all markdown blog posts sorted by date
const result = await graphql(
{ allMicrocmsBlog(sort: { fields: [createdAt], order: DESC }) { edges { node { id blogId createdAt } previous { id } next { id } } } }
)
if (result.errors) {
reporter.panicOnBuild(
There was an error loading your blog posts
,
result.errors
)
return
}
const edges = result.data.allMicrocmsBlog.edges
// Create blog posts pages
// But only if there's at least one markdown file found at "content/blog" (defined in gatsby-config.js)
// context
is available in the template as a prop and as a variable in GraphQL
if (edges.length > 0) {
edges.forEach(({ node: post, previous, next }, index) => {
// const previousPostId = index === 0 ? null : edges[index - 1].id
const previousPostId = previous ? previous.id : null
// const nextPostId =
// index === edges.length - 1 ? null : edges[index + 1].id
const nextPostId = next ? next.id : null
createPage({
// ページのURLのパス
path: post.blogId,
// ページコンポーネント
component: blogPost,
// ページコンポーネントに渡すデータ
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
})
}
}
...
次に、ページコンポーネントに指定したsrc/templates/blog-post.js
で各ページの内容を記載します。
blog-post.js
import * as React from "react"
import { Link, graphql } from "gatsby"
import Bio from "../components/bio"
import Layout from "../components/layout"
import Seo from "../components/seo"
const BlogPostTemplate = ({ data, location }) => {
console.log(data)
const post = data.microcmsBlog
const siteTitle = data.site.siteMetadata?.title || `Title`
const { previous, next } = data
return (
<Layout location={location} title={siteTitle}>
<Seo
title={post.title}
description={post.description || "default description"}
/>
<article
className="blog-post"
itemScope
itemType="http://schema.org/Article"
>
<header>
<h1 itemProp="headline">{post.title}</h1>
<p>{post.createdAt}</p>
</header>
<section
dangerouslySetInnerHTML={{ __html: post.bodyHtml }}
itemProp="articleBody"
/>
<hr />
<footer>
<Bio />
</footer>
</article>
<nav className="blog-post-nav">
<ul
style={{
display: `flex`,
flexWrap: `wrap`,
justifyContent: `space-between`,
listStyle: `none`,
padding: 0,
}}
>
<li>
{previous && (
<Link to={previous.id} rel="prev">
← {previous.title}
</Link>
)}
</li>
<li>
{next && (
<Link to={next.id} rel="next">
{next.title} →
</Link>
)}
</li>
</ul>
</nav>
</Layout>
)
}
export default BlogPostTemplate
// `gatsby-node.js`の`createPage()`で`context`として設定した値を引数として使用できる
export const pageQuery = graphql`
query BlogPostById(
$id: String!
$previousPostId: String
$nextPostId: String
) {
site {
siteMetadata {
title
}
}
microcmsBlog(id: { eq: $id }) {
id
title
bodyHtml
createdAt
}
previous: microcmsBlog(id: { eq: $previousPostId }) {
id
title
}
next: microcmsBlog(id: { eq: $nextPostId }) {
id
title
}
}
`
一覧ページから、個別の記事へのリンクをクリックすると、
記事詳細ページにmicroCMSで設定したコンテンツが表示されているのがわかります。
Cloudflare Pagesへのデプロイ
公式からアカウントを新規登録し、連携するGitHubリポジトリや環境変数などを設定すると、
あっという間にビルドとデプロイが始まります。
17:00:40.303 ERROR
17:00:40.303
17:00:40.303 Gatsby requires Node.js 14.15.0 or higher (you have v12.18.0).
17:00:40.303 Upgrade Node to the latest stable release: https://gatsby.dev/upgrading-node-js
nodeのバージョンがデフォルトでv12.18.0
なっているらしく、エラーが出るので、環境変数に NODE_VERSION
を追加します(私は16.13.2
を指定しました)
ビルドが成功したので、Visit Site
というリンクをクリックすると、
デプロイが成功していることがわかります🎉
他
とりあえず、最小の設定でCloudflare Pages x microCMS x GatsbyJSでブログを作ってみました。
独自ドメインやデプロイ・microCMSでのプレビューの設定やTypeScript化など、まだまだやらなければならないことはありますが、一旦ここまでにしようと思います。
Discussion