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

先日、JAMStackなポートフォリオサイトに一新しました。以下のリンクから確認できます。
→[Gurutaka Portfolio](https://gurutaka.xyz/)

使用した技術はこちら！

- Nuxt
- Contentful
- Netlify

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

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

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

## 基本用語について

### JAMStackとは？
JAMStackとは、アーキテクチャの１つで、**J**avaScript **A**PIs **M**arkup になぞった名前です。

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

- JavaScript：クライアントサイド
- APIs：再利用可能
- Markup:html（静的ファイル）のみの構成

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

メリットとして、

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

参考：[【入門】Nuxt.js + Contentful + Netlify で始める、JAMstack な CMS 構築 - Qiita](https://qiita.com/isihigameKoudai/items/3e45ade7c438176a4cc9)

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

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

参考：[公式 Jamstack | JavaScript, APIs, and Markup](https://jamstack.org/)
### ヘッドレスCMSとは？
JAMStackについて調べてみると、ヘッドレスCMS（Contents Management System）というワードが出てきます。一言でいうと、コンテンツだけ管理するシステムです。ヘッドレスは、ビューがないという意味合いで使われています。

クライアント側はAPIでコンテンツを取得すれば良いので、クライアントサイドに依存することなく開発できます。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/s/special-moucom/20190423/20190423230030.png)
引用：[ヘッドレスCMSとは？ヘッドレスCMSの概要について調べてみた - Try T.M Engineer Blog](https://kodak.hatenablog.com/entry/2019/04/24/005631)

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

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314351/290c2ab6-b9a8-0b23-fa9e-c16ee4d4b9ca.png)
引用：[Contentfulとは？ヘッドレスCMSって何？誰でもわかるように解説してみる | ぐるたかログ](https://gurutaka-log.com/contentful-headless-cms-summary)

参考：[JAMstackってなに？実践に学ぶ高速表示を実現するアーキテクチャの構成 - エンジニアHub｜若手Webエンジニアのキャリアを考える！](https://employment.en-japan.com/engineerhub/entry/2019/12/10/103000)

## 実装周りの技術について

### アーキテクチャ
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314351/b9704d59-9baf-bd7c-76f1-7e79fdf474e1.png)

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

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

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

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

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

![](https://gurutaka-log.com/wp-content/uploads/73187d8c-d51a-45b6-bace-614437084ddf-1920x1079r.png)

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314351/4e7b1236-6da4-6110-9ab1-97ad45a3f1e0.png)

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

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

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

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

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

引用：[Contentfulの料金と使い方を整理しつつ、Nuxt.jsと組み合わせてブログを作る - Qiita](https://qiita.com/nishinoshake/items/466db319ec485ebc7db8)

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

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

### Nuxt

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

```
$ npm run generate 
```

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

→[NuxtにContentfulを設定する方法。導入からデータ取得までの流れをまとめてみた【スクショあり】 | ぐるたかログ](https://gurutaka-log.com/nuxt-contentful-setting)

```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](https://www.contentful.com/developers/docs/javascript/tutorials/integrate-contentful-with-vue-and-nuxt/)

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

- [nuxt.js(v2)でgenerate納品する前にやっておきたい設定 - Qiita](https://qiita.com/amishiro/items/11bd642728f6b5838189)
- [nuxt.js(v2)でSEOに必要なmeta(OGP)を入れたい - Qiita](https://qiita.com/amishiro/items/b7260116b282d2cf2756)

余談ですが、お恥ずかしい話、OGP設定でprefix属性を忘れて、四苦八苦しました。OGP生成する方は要チェックです！
[OGPにつけるprefix属性とは何か調べてみた。 - Qiita](https://qiita.com/t-fujio/items/8a237494498f42591b36)

また、ビルドした後の静的ファイルをNuxtと切り離して確認する際は、http-serverを使っています。
[nuxt generateで生成した静的ファイルをhttp-serverでホスティングする #nuxtjs - ジムには乗りたい](https://su-kun1899.hatenablog.com/entry/2018/01/26/230000)

### Netlify
以下の記事に従って、進めていけば超簡単にデプロイできます！
→[【Netlify】Github連携でWEBサイトを公開する - Qiita](https://qiita.com/NaokiIshimura/items/9f12805af85c9be22814)

Contentful WebhookでNetlifyと連携する方法は自分のブログにまとめています！
→[【Contentful Webhook】コンテンツ変更を検知し、Netlifyで自動でビルドさせる方法 | ぐるたかログ](https://gurutaka-log.com/contentful-netlify-webhook)

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

こちらもNetlify Formsでお問い合わせフォームを設置する方法を書いたので、参考になればと思います。
→[Netlify Formsを使って、お問い合わせフォームを設置する方法 | ぐるたかログ](https://gurutaka-log.com/netlify-nuxt-contact-form)

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

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

<img width="459" alt="Build___deploy___Settings.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314351/713b6110-7a51-883a-8d31-99d9d1a94d2d.png">

##　最後に

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

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

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

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

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

## 参考リンク
[【入門】Nuxt.js + Contentful + Netlify で始める、JAMstack な CMS 構築 - Qiita](https://qiita.com/isihigameKoudai/items/3e45ade7c438176a4cc9)