2021-09-04
2021-11-11
Next.jsでGraphCMSを使ったブログの作成
Next.js,
frontend,
React.js,
TypeScript,
GraphQL,
今回は、GraphCMS を使って Next.js アプリにブログを導入する方法を書いていきます。
GraphCMS とは
名前の通り、GraphQL クエリを使える HeadlessCMS になります。見た目の UI が綺麗で使いやすいです。
ただ、google 日本語翻訳をしたままスキーマを作成したりすると、クラッシュする頻度が多いのがネックです(自分の Macbook だけなのかもしれません...)。
ブログの作成
Next.js の立ち上げ
まずは、create-next-app でプロジェクトを立ち上げます。 「graphcms_blog」の箇所は任意の名前をつけてください。
yarn create next-app graphcms_blog --typescript
そのプロジェクトに移動します。
cd graphcms_blog
yarn dev でプロジェクトを起動しましょう。
localhost:3000 にアクセスしてこの画面が表示されれば OK です。 Next.js の使用経験がある人ならお馴染みのページですね。
GraphCMSで記事の作成
次にブログの記事を GraphCMS で作成します。
プロジェクト作成
こちらでGraphCMSへサインアップします。
サインアップが完了したらプロジェクトを作成しましょう。
新しいプロジェクトを作成します。Blank を選択。
プロジェクト名を任意で入力し、リージョンを Tokyo に指定します。なぜかアジアでは東京リージョンのみ選択できます。
サービスプランを選択します。 個人利用でしたら、「Free forever」を選択。
ここはそのまま。ここで他のユーザーを招待して複数人開発することができます。
この手順通りに行っていきましょう。
ちなみに、右から出てくるアナウンスは普通に閉じるだけでは永遠と出てくるので、表示しないボタンを押しましょう。
今回の記事は簡単に、以下の構成にします。
- タイトル
- コンテンツ内容
- 画像
この時、このタイトル、コンテンツ、画像をまとめた一塊を「Model」といいます。 そして、タイトル、コンテンツ、画像、それぞれを「Schema」といいます。
Model の作成
サイドバーから schema を選択し、create Model を選択。
Display name を入力します。ここでは blog という名前にします。 API ID、Plural API ID は自動で出力されるので、そのままで大丈夫です。 Description は記入は任意になります。
Create Model を選択します。
Schema の作成
次に作成したモデルに Schema を作成していきます。 右側の「Add Fields」から型を選択できます。
一つ目の、タイトルを作成します。
Add Fields から「Single line text」を選択します。 Display name をつけます。ここでは title とします。API ID は自動で付与されます。Description は記入してもしなくても大丈夫です。
Settings の隣の「VALIDATIONS」を選択します。
Settings の隣からバリデーションをかけられるので title は、一番上の Make field required を選択しましょう。 指定することで、この Schema を必須項目にすることができます。 チェックを入れたら、Create を選択しましょう。
他にも、文字数を制限したりなどのバリデーションをかけられるので、気になる人は見てみてください。
タイトルの他も同じように作成していきましょう。
スキーマ | Display name | fields | 必須かどうか |
---|---|---|---|
タイトル | title | Single line text | 必須 |
コンテンツ | content | markdown | 必須 |
画像 | image | Asset picker | 任意 |
このような感じになればオッケーです。
また、「Show system Fields」を開くと、自動で作成されるスキーマの一覧が見れます。 「createdAt」を作らなかったのは、既にあるからです。
サイドバーからコンテンツを選択し、create item を押します。
タイトル、コンテンツ内容、画像を作成し、記事を作成します。
緑色の「Save and publish」を選択
画像を公開するか聞かれるのでチェックを入れましょう。
同じようにコンテンツを 4 つほど作成しましょう。
クエリを投げる
Playground でクエリを投げてみましょう。 こちらで、graphql クエリを投げた時の挙動、結果を試すことができるのでかなり便利です。
下記画像のクエリを投げてみましょう。(GlaphQLクエリの記述については今回取り扱いません)
クエリが正常に取得できているとこのようになるはずです。
Permissionの編集
サイドバーの setting から「public content API」を選択
「Create permission」を選択
read と publish 権限を All にして Create を選択。
最後に API からコンテンツ API をコピーしておきます。
コードの変更
Next.js の project に戻ります。
apollo-client
と graphql
をインストールします。
yarn add @apollo/client graphql
API を.env に記述しましょう。
.env
NEXT_PUBLIC_GRAPHCMS_API=<先ほどコピーしたAPI>
apollo-client の設定を行います。
libs/apollo-client.tsx
import { ApolloClient, InMemoryCache } from "@apollo/client"; const client = new ApolloClient({ uri: process.env.NEXT_PUBLIC_GRAPHCMS_API, cache: new InMemoryCache(), }); export default client;
Next.js では外部から画像を読み込む際はドメインを config に設定する必要があります。 next.config.js で設定していきます。
next.config.js
module.exports = { reactStrictMode: true, images: { domains: ["media.graphcms.com"], }, };
index.tsxの変更
設定が終わりましたので、index.tsx を変更していきます。
pages/index.tsx
import type { NextPage } from "next"; import Image from "next/image"; import Link from "next/link"; import styles from "../styles/Home.module.css"; import client from "../libs/apollo-client”; import { GetStaticProps } from "next"; import { gql } from "@apollo/client"; type Blog = { id: string; title: string; createdAt: string; content: { html: JSX.Element }; image: { url: string }; }; type Props = { data: { blogs: Blog[] }; }; export const getStaticProps: GetStaticProps<Props> = async () => { const { data } = await client.query({ query: gql` query MyQuery { blogs { id createdAt title content { html } image { url } } } `, }); return { props: { data: data, }, }; }; const Home: NextPage<Props> = ({ data }: Props) => { return ( <div className={styles.container}> <main className={styles.main}> <h1 className={styles.title}>GraphCMS Blog</h1> <div className={styles.grid}> {data.blogs.map((value: Blog) => { const d = new Date(value.createdAt); const createdDate = String(d.getFullYear()) + "." + String(("0" + (d.getMonth() + 1)).slice(-2)) + "." + String(("0" + d.getDate()).slice(-2)); return ( <Link passHref key={value.title} href={`/articles/${value.id}`}> <div className={styles.card}> <p>{createdDate}</p> <h2>{value.title}</h2> <Image alt={value.title} src={value.image.url} width={350} height={190} /> </div> </Link> ); })} </div> </main> </div> ); }; export default Home;
createdAt は日付に直します。日付が一桁だった場合は左側に0を追加するように設定します。
今回は、SSG でデータを取得するため、getStaticProps 内でクエリを投げます。
Next.js の getStaticProps のドキュメントはこちら
console.log で(data)の中を見てみましょう。
しっかりと取得できていることが確認できます。
スタイルの変更
css を変更します。
styles/Home.module.css
.main { padding: 1rem 0; flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; } .title { font-size: 2.5rem; } .grid { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; max-width: 800px; margin-top: 1rem; } .card { margin: 0.5rem; padding: 1rem; text-align: left; color: inherit; text-decoration: none; border: 1px solid #eaeaea; border-radius: 10px; transition: color 0.15s ease, border-color 0.15s ease; width: 45%; } .card:hover, .card:focus, .card:active { color: #0070f3; border-color: #0070f3; } .card h2 { margin: 0 0 0.5rem 0; font-size: 1.5rem; } .card p { margin: 0; font-size: 0.8rem; line-height: 1.0; } @media (max-width: 600px) { .grid { width: 100%; flex-direction: column; } }
このようになればオッケーです。
以上で、graphCMS からデータを表示することができました。お疲れ様でした。
まだ、ページ先の遷移がないので、次回はそちらを作っていきたいと思います。
ではまた。