【JAMStack】Nuxt×Contentful×Netlifyでポートフォリオサイトを一新。使用技術まとめてみる


先日、JAMStackなポートフォリオサイトに一新しました。以下のリンクから確認できます。
Gurutaka Portfolio

使用した技術はこちら!

  • Nuxt
  • Contentful
  • Netlify

作り直した理由は以下のとおりです。

  • JAMStackというアーキテクチャが気になったこと
  • Worksコンテンツをローカルで編集するのが億劫
  • ヘッドレスCMS(Contentful)に興味あり

ここでは、JAMStackに初めて触れた私が、ポートフォリオサイト開発で得られた技術的知見を紹介していきます。
誤りなどありましたら、コメントでご指摘いただけると幸いです。

基本用語について

JAMStackとは?

JAMStackとは、アーキテクチャの1つで、JavaScript APIs Markup になぞった名前です。

簡単にまとめると、こんなイメージです。

  • JavaScript:クライアントサイド
  • APIs:再利用可能
  • Markup:html(静的ファイル)のみの構成

JavaScript側でフロント周りを実装し、コンテンツはAPIで取得。そして、レンダリングでhtmlをブラウザ上に描画します。

メリットとして、

  • パフォーマンス良い
  • ハイセキュリティ
  • スケーリングが容易
  • 開発体験が良い

参考:【入門】Nuxt.js + Contentful + Netlify で始める、JAMstack な CMS 構築 - Qiita

静的ファイルを事前にビルドして描画するので、描画まで早いです。
(私のサイトはまだまだサイト高速化の改善の余地ありですが、SPAだった時よりはかなり早くなっています)

特に感じたのは開発体験の素晴らしさ!コンテンツもAPIで取得するだけなので、フロントに集中できます。

参考:公式 Jamstack | JavaScript, APIs, and Markup

ヘッドレスCMSとは?

JAMStackについて調べてみると、ヘッドレスCMS(Contents Management System)というワードが出てきます。一言でいうと、コンテンツだけ管理するシステムです。ヘッドレスは、ビューがないという意味合いで使われています。

クライアント側はAPIでコンテンツを取得すれば良いので、クライアントサイドに依存することなく開発できます。

引用:ヘッドレスCMSとは?ヘッドレスCMSの概要について調べてみた - Try T.M Engineer Blog

今回はヘッドレスCMSを提供しているサービスの1つであるContentfulを使用。開発もフロントだけなので工数もかかりませんでした。


引用:Contentfulとは?ヘッドレスCMSって何?誰でもわかるように解説してみる | ぐるたかログ

参考:JAMstackってなに?実践に学ぶ高速表示を実現するアーキテクチャの構成 - エンジニアHub|若手Webエンジニアのキャリアを考える!

実装周りの技術について

アーキテクチャ

ポートフォリオサイトのアーキテクチャです。

  • クライアントサイド:Nuxt
  • ヘッドレスCMS:Contentful
  • サーバー:Netlify

Webhookを使い、Githubで管理しているソースが変更、またはContentfulの特定コンテンツが変更・追加・削除されると、Netlifyに自動で通知され、ビルド&デプロイされて最新版になるように設定しています。

Contentful

Contentfulには専門用語があり、所見だとわかりにくいので、図でまとめてみました。

以下キーワードです!
- スペース
- コンテンツモデル
- コンテンツ

名前 意味
スペース Githubでいうリポジトリのような役割。コンテンツを管理する場所
コンテンツモデル コンテンツの雛型(テンプレート)
コンテンツ コンテンツモデルから作り出された情報(コンテンツ)

簡単にまとめると
- スペースで色んなコンテンツを管理(最初に自動でスペース1つ分作られます)
- コンテンツモデルでコンテンツの雛型を作成(例えば、ブログ投稿のテンプレートなど)
- コンテンツモデルからコンテンツを作っていく(ブログでいえば、投稿記事など)

以下の記事にcontentfulの始め方や概念をまとめているので、参考になれば嬉しいです。
- Contentfulとは?ヘッドレスCMSって何?誰でもわかるように解説してみる | ぐるたかログ
- 【初心者向け】Contentfulの始め方。コンテンツモデルの作成や投稿、APIキーの場所などまとめ【使い方】 | ぐるたかログ

使用料金に関しては、個人でやる分には無料枠で十分いけます。

24個のコンテンツタイプ
5000個のレコード
10人のユーザー
1つのロール(ユーザー権限)
2つの環境(master/stagingとか)
2つのロケール(多言語対応)

引用:Contentfulの料金と使い方を整理しつつ、Nuxt.jsと組み合わせてブログを作る - Qiita

他にもコンテンツモデルのバリデーション機能も豊富で、コンテンツ同志の紐付け(reference)機能も使えます。更にブランチ機能まであるという!

わりと多機能なので、実際に使いながら色々と試してみると良いでしょう!

Nuxt

Nuxtで静的ファイルをビルド(プリレンダリング)するのは簡単です。以下のコマンドを使用すればOK

$ npm run generate 

NuxtにContentfulを導入する方法はブログに図解でまとめています。データ取得までのサンプルコードも載せているので、ご興味ある方はチェックしていただけますと嬉しいです。

NuxtにContentfulを設定する方法。導入からデータ取得までの流れをまとめてみた【スクショあり】 | ぐるたかログ

pages/index.vue
<script>
import contentfulClient from '@/plugins/contentful'

export default {
  asyncData({ env }) {
    return contentfulClient
      .getEntries()
      .then((entries) => {
        console.log(entries.items)
        return {
          ssample: entries.items
        }
      })
      .catch(console.error)
  }
}
</script>

ブログには掲載していないのですが、asyncDataでcontentfulから複数のHTTPリクエストを扱う場合は、Promise.allを使うと、スマートにかけます。

sample.vue
<template>
  <div>
    <!-- render data of the person -->
    <h1>{{ person.fields.name }}</h1>
    <!-- render blog posts -->
    <ul>
      <li v-for="post in posts">
        {{ post.fields.title }}
      </li>
    </ul>
  </div>
</template>

<script>
  import {createClient} from '~/plugins/contentful.js'

  const client = createClient()

  export default {
    // `env` is available in the context object
    asyncData ({env}) {
      return Promise.all([
        // fetch the owner of the blog
        client.getEntries({
          'sys.id': env.CTF_PERSON_ID
        }),
        // fetch all blog posts sorted by creation date
        client.getEntries({
          'content_type': env.CTF_BLOG_POST_TYPE_ID,
          order: '-sys.createdAt'
        })
      ]).then(([entries, posts]) => {
        // return data that should be available
        // in the template
        return {
          person: entries.items[0],
          posts: posts.items
        }
      }).catch(console.error)
    }
  }
</script>

引用:Integrate Contentful with Nuxt.js – Contentful

また、ビルドする前にOGPなど色々と設定しました。その際に、こちらの記事が丁寧にまとめられていて、凄く参考になりました!

余談ですが、お恥ずかしい話、OGP設定でprefix属性を忘れて、四苦八苦しました。OGP生成する方は要チェックです!
OGPにつけるprefix属性とは何か調べてみた。 - Qiita

また、ビルドした後の静的ファイルをNuxtと切り離して確認する際は、http-serverを使っています。
nuxt generateで生成した静的ファイルをhttp-serverでホスティングする #nuxtjs - ジムには乗りたい

Netlify

以下の記事に従って、進めていけば超簡単にデプロイできます!
【Netlify】Github連携でWEBサイトを公開する - Qiita

Contentful WebhookでNetlifyと連携する方法は自分のブログにまとめています!
【Contentful Webhook】コンテンツ変更を検知し、Netlifyで自動でビルドさせる方法 | ぐるたかログ

またNetlifyにはNetlify Formsがあります。せっかくなので、Netlify Formsを使って、お問い合わせフォームをポートフォリオサイトに組み込みました。JavaScriptだけで、お問い合わせフォームもできるなんてビックリです。

こちらもNetlify Formsでお問い合わせフォームを設置する方法を書いたので、参考になればと思います。
Netlify Formsを使って、お問い合わせフォームを設置する方法 | ぐるたかログ

そして最後に、詰まった点を1つ紹介。 Netlifyにビルドする際に、env周りで設定したContentful関連の環境変数をNetlifyにも必ず登録しましょう。

登録しないと、APIでコンテンツ情報を取得できなくなります!私は初心者すぎて、小一時間くらい消耗しました…。

 最後に

JAMStackなポートフォリオサイトを開発してみて、感動しました。JavaScriptだけでここまで作れるなんて、すごい世界だなと。

そして可能性を感じました。

こちらの記事にも書かれていますが、今後ノーコード(GUI)でフロントが作れてAPIでコンテンツ取得までできれば、エンジニアでなくても、メディアサイトのようなものが作れるわけです。

今後のJAMStackの動向も楽しみです!

ここまでご覧いただき、ありがとうございました。

参考リンク

【入門】Nuxt.js + Contentful + Netlify で始める、JAMstack な CMS 構築 - Qiita