Table of Contents
はじめに
株式会社FundastAの片田です!
業務ではサーバーサイドを担当しておりますが、モダンフロントエンドにも興味があります。
そんな折、ちょうど良いところにブログを始めたい友人がおりましたので、NuxtとContentfulでナウいブログを構築してみました!
実際に作成したブログは下記URLからご覧いただけます。
https://vigilant-lichterman-42a0e2.netlify.com/
本記事では主にContentfulAPIを使ったブログ構築を私なりに噛み砕いて紹介していきます。
技術選定について
なぜNuxt.jsなのか?
- 勉強中のNuxt.jsでアウトプットしたかった。
- Vueより簡単。
- 初期表示速度も欲しかったので、SSRなブログを作ってみたかった。
SSRとは?
みなさんご存知かと思いますが、SSRって何?ってところを深堀しておきます。 こちらの記事を主に参考にさせていただきました。
私なりに解釈すると、SSRとは、本来クライアントがレンダリングする部分をサーバーでレンダリングしておき、クライアントに返す ようにするものです。
SSR(サーバーサイドレンダリング)の名前のとおりです笑
SSRアプリケーションにすることで、SPA(シングルページアプリケーション)のデメリットである、初期表示速度が遅いことや、SEO的に不利になる(クローラーがうまくクローリングしてくれない)ことを解消できます。
(今はSPAでもSEO的に不利になることはない、という情報を目にしたことがありますが、ここでは言及しません)
なぜContentfulなのか?
- これからWordPress独自の仕様や言語(PHP)を学ぶのは嫌だ。 → CMS側の学習コストなどはとくにかからない。
- 実際にブログを書くのは非エンジニアの友人なので、わかりやすいUIが整ってる方が良かった。
- ヘッドレスCMSって響きかっこいい。なんか使ってみたかった。
- フロント以外の全てのことをcontentfulで済ませることができるし、細かいところまで設定&カスタマイズできるところが面白そう。
ヘッドレスCMSとは?
そもそも、CMSとは何でしょう?
ブログを運営したことある方なら、真っ先にWordPressが頭に浮かびますよね。
CMS(コンテンツマネジメントシステム)とは、Web制作の知識がなくても簡単にブログやWebサイトを構築、管理、更新できるシステムのことを言います。
今回はただのCMSではなく、ヘッドレスCMSです。
ヘッドレスCMSは、ビュー(フロント)がないCMSのことだと認識しています。
今回使用したContentfulも、記事の更新、管理は簡単にでき、管理画面は用意されているものの、実際にユーザーに表示される部分は用意されていません。
その代わりに、APIとして記事の情報を取得することができたりするので、フロントエンドは自身で作り込むことができるのです。
なぜElementUIなのか?
- 手軽に整ったUIを試してみたかった。
- Vuetifyは使ったことあるので、使ったことないものを使ってみたかった。
なぜNetlifyなのか?
- GitHubと連携して、ほぼ設定いらずで自動デプロイできるのが魅力的。(最高)
- 自動でセキュアなURLにしてくれるのも魅力的。
- しばらくは無料枠のまま使い続けられそうだったから。
- firebaseは使ったことあるから、別のもの使ってみたかった。
- なんか使ってみたかった。
ContentfulAPIについて
今回実装したこと
- 記事データを全て取得して、記事一覧を表示する
- 記事データを全て取得して、記事内容を表示する
- 記事にタグを付けられる様にして、記事データと一緒にタグを取得、表示する
- タグデータを全て取得して、タグ一覧を表示する
- タグで記事を検索する
- 記事名のキーワードで記事を検索する
NuxtアプリケーションとContentfulAPIの連携方法について
フロントとAPIの連携に関しては、他のQiita記事やWebサイトで多くの方が解説されているので、詳細は割愛します。 簡単な流れとしては、
- Nuxtアプリケーションにnpmを使ってContentfulをインストールする
- pluginsディレクトリにcontentful.js等の名前で設定ファイルを作成
- nuxt.config.jsとかに設定を反映したりなんやらする
- あとはビューでAPI叩くだけ!
詳しくはこちらの記事を参考にさせていただきました。
記事データの取得について
記事データを取得しているソースコードはこちらです!
1 2 3 4 5 6 7 8 9 10 11 12 |
<script> asyncData({ env }) { return client .getEntries({ content_type: env.CTF_BLOG_POST_TYPE_ID }) .then(entries => { return { posts: entries.items } }) .catch(console.error) } </script> |
asyncDataを使って非同期でAPIと通信します。(引数に渡しているenvはcontentfulのapiKeyなどを隠してあるdotenvの内容です) 戻り値のclientですが、plugins/contentful.jsで定義している
1 |
const client = contentful.createClient(config) |
を呼び出しています。
.getEntriesでは取得してくる記事のフィルタリングを行っています。
今回は記事一覧なので、cntentfulの、content modelをblogPost(任意の名前)に指定して、ブログ記事のみ取得しています。
.thenで実際に取得してきたデータをposts変数に詰めて返します。
contentfulAPIのデータはJsonで帰ってくるので、後々扱いやすい様に取得する値を絞っています。
エラーをハンドリングした際はconsole.logで出力します。
あとはビュー側で取得してきたpostsのデータを表示するだけ!
1 2 3 4 5 |
<template> <ul> <li v-for="(post, i) in posts" :key="i">{{ post.fields.name }}</li> </ul> </template> |
ビューのソースコードは適当ですが、こんな感じでデータを表示することができます。
記事とタグの関連付けと、タグデータの取得について
contentfulで記事のタグ付けを行うには、contentfulの管理画面で、tag用のcontent modelを追加します。
管理画面がらいくつかタグを新規作成したら、 記事のcontent modelを編集 → refarencesで先ほど作成したtag 用のcontent modelを関連付け
これで記事にタグ付けができる様になります!
タグデータの取得は二通りあり、
ひとつは前項で取得した記事データの中からタグのデータを抽出する方法。
もうひとつはタグのデータのみを全て取得する方法です。
まずは記事データの中からタグのデータを抽出する方法についてですが、 これは先ほど取得したjsonデータの中にその記事に関連づけられたタグのデータも含まれていますので、 jsonをみながらビューで表示してやれば良いです。
content modelをどのように作成するかによってデータは異なりますが、私の場合は、
1 2 3 4 5 |
<template> <ul> <li v-for="(post, i) in posts" :key="i">{{ post.fields.tag.fields.name }}<li> </ul> </template> |
で取得しています。
そしてタグのデータのみを全件取得する方法ですが、 これも前述した記事を全件取得するコードの、content modelを指定している箇所をtag用のcontent modelを指定する様に変更するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 |
<script> asyncData({ env }) { return client .getEntries({ content_type: env.CTF_TAG_TYPE_ID }) .then(entries => { return { tags: entries.items } }) .catch(console.error) } </script> |
具体的にいうと、getEntriesメソッドの引数に渡す値でフィルタリングできるので、そこを予め取得しておいたtag用のcontent modelのidに差し替えました。
こうすることでタグデータのみ全件取得することができるので、あとは取得したデータをtags変数に格納すれば完成です。
ビューでの表示は、記事と同じ様に、
1 2 3 4 5 |
<template> <ul> <li v-for="(tag, i) in tags" :key="i">{{ tag.fields.name }}</li> </ul> </template> |
で表示されます!
おわりに
Nuxt.jsのアウトプットもできたし、それなりにかっこいいブログも作れたし(自己満足)、やってよかったです。
弊社の当ブログはVuePressというVue製の静的サイトジェネレータを使用して作成したので、後日記事にまとめてみます!