Nuxt.js+Contentful+NetlifyでサーバーレスなSPAサイトを作成する

こんにちは!
株式会社SCOUTER開発部フロントエンドエンジニアの佐藤(@r_sato1201)です

先日、社内でプログラミング歴が浅い社員対象の、初学者LT大会というものが開催されました。 LT大会の様子は後日このブログにて公開されると思いますが、 今回はそのLT大会で私が作成したものを、使った技術の紹介も含めて紹介したいと思います。
主にNuxtとNetlifyについて紹介します。

作成物

休日に活動しているバンドのHPを作成しました。

f:id:ryonnsui1201:20181224165412p:plain
bokunofuneHP

技術構成

Nuxt + Contentful + Netlify

この構成を選んだ理由は大きく2点あります。

HPの更新を誰でも更新できるようにしたかった

バンドHPでは主に、ライブ情報や発売したCDなどの情報を定期的に更新する必要があります。 その更新を、私以外のバンドメンバーでも更新できるようにしたかった為、CMS化することを考えました。 その中で、ContentfulはAPIファーストでコンテンツの作成・管理を簡単にできるので選択しました。

サーバーを自前で用意・運用したくなかった

上記の通りなのですが、サーバーを自前で運用するのはコストもかかりますし、知見もなかったので 静的サイトホスティングサービスであるNetlifyを選択しました。 GitHubリポジトリからwebhookを受け取ると自動でリポジトリをビルドやデプロイしてくれるので非常に便利なサービスです。

1.Nuxtでサイトの作成

Nuxtプロジェクト作成

yarn create nuxt-app <プロジェクト名>

まずは上記コマンドでNuxtプロジェクトを作成します。

layoutの作成

各ページ共通であるヘッダー、フッターをレイアウトテンプレートに記述しました。

default.vue

<template>
  <div>
    <Header/>
    <nuxt/>
    <Footer/>
  </div>

</template>

<script>
import Header from '~/components/item/Header.vue'
import Footer from '~/components/item/Footer.vue'

export default {
  components: {
    Header,
    Footer,
  },
}
</script>

ヘッダー、フッター部分のコードは割愛します。

Contentfulの設定

Contentfulについて

Nuxtでプロジェクトを作り、外見をつくったら次はContentfulの設定です。 Contentfulはコンテンツを管理するためのREST APIを提供してくれます。 f:id:ryonnsui1201:20181225115721p:plain

Contentfulの概念は上図のようになっています。 各々をイメージで説明すると

Space:コンテンツを管理する単位
ContentModel:データベースのテーブル定義のようなもので、テーブルのカラム定義を設定する場所
Entry:ContentModelに定義したテーブルのデータ
となります。
Spaceの作成→ContentModelの作成→Entryの作成という順序でコンテンツを作成します。
次に、Contentfulを呼び出す用のプラグインcontentful.jsを作成します

contentful.js

const contentful = require('contentful')

const config = {
  space: process.env.CTF_SPACE_ID,
  accessToken: process.env.CTF_CDA_ACCESS_TOKEN,
}

module.exports = {
  createClient() {
    return contentful.createClient(config)
  },
}

次に、Contentfulと接続するためのAPI keyを取得し、接続設定を以下のように.envに記述します

.env

CTF_SPACE_ID="Your Space ID"
CTF_CDA_ACCESS_TOKEN="Your Access Token"
CTF_BLOG_POST_TYPE_ID="Your Post Type ID"

nuxt.config.jsにて先程.envに記述した内容をenvプロパティにて呼び出します。

nuxt.config.js

const config = require('./.contentful.json')

module.exports = {
  // ...
  env: {
    CTF_SPACE_ID: config.CTF_SPACE_ID,
    CTF_CDA_ACCESS_TOKEN: config.CTF_CDA_ACCESS_TOKEN,
    CTF_BLOG_POST_TYPE_ID: config.CTF_BLOG_POST_TYPE_ID
  }
  // ...
}

最後に、Vueファイルを記述し記事を取得します。 asyncData内でContentfulから記事情報を取得し、Liveコンポーネントに渡しています。
※Vueファイルは分かりやすくするため、簡略化しています

pages/live/index.vue

<template>
  <div class="container">
      <live
        v-for="post in posts"
        :key="post.fields.slug"
        :image="post.fields.image"
        :title="post.fields.title"
        :place="post.fields.place"
        :fee="post.fields.fee"
      />
  </div>
</template>

<script>
import Live from '~/components/Live'
import { createClient } from '~/plugins/contentful'

const client = createClient()
export default {
  transition: 'slide-left',
  components: {
    Live,
  },
 asyncData({ env }) {
    return client
      .getEntries({
        content_type: env.CTF_BLOG_POST_TYPE_ID,
        order: '-fields.date',
      })
      .then(entries => {
        return {
          posts: entries.items,
        }
      })
      .catch(console.error)
  },
}
</script>



components/Live.vue

<template>
      <div class="live-card">
        <div class="live-card_image">
          <img :src="image.fields.file.url">
        </div>
        <div class="live-card_contents">
          <p class="live-card_title">{{ title }}</p>
          <p class="live-card_place">{{ place }}</p>
          <p class="live-card_fee">{{ fee }}</p>
        </div>
      </div>
</template>
<script>
export default {
  props: {
    image: {
      type: Object,
    },
    title: {
      type: String,
    },
    place: {
      type: String,
    },
    fee: {
      type: String,
    },
  }
}

これでContentfulの設定は完了しました。

※詳しくは、Contentful公式ドキュメントに詳しく書かれているので参照して下さい。

Netlifyの設定

Netlify Formsについて

Netlifyを選んだ理由として、サーバーレスで実装できる以外にもフォームが簡単に実装できることが挙げられます。
HTMLの

タグの属性にnetlifyと追加で記述することで、そのフォームが動きます。 以下は公式ドキュメントの例です。

<form name="contact" method="POST" data-netlify="true">
  <p>
    <label>Your Name: <input type="text" name="name" /></label>   
  </p>
  <p>
    <label>Your Email: <input type="email" name="email" /></label>
  </p>
  <p>
    <label>Your Role: <select name="role[]" multiple>
      <option value="leader">Leader</option>
      <option value="follower">Follower</option>
    </select></label>
  </p>
  <p>
    <label>Message: <textarea name="message"></textarea></label>
  </p>
  <p>
    <button type="submit">Send</button>
  </p>
</form>

上記のように記述するだけで、NetlifyのFromページ上で送られた情報が確認できます。

サイトの作成

最後にNetlifyの設定について書きたいと思います。 「New Site From Git」を押下するとリポジトリ選択画面に移動するので、Nuxtプロジェクトをプッシュしたリポジトリを選択してください。 f:id:ryonnsui1201:20181224224147p:plain

次に、デプロイするブランチを選択して下さい。 基本的にはmasterでいいと思います。 f:id:ryonnsui1201:20181224225549p:plain

デプロイブランチを選択したら、ビルドの設定を行います。 今回は、Nuxtから静的サイトジェネレートするので nuxt generateと記述をします。
nuxt generateによってdistディレクトリが生成されるので、Publish Directoryにはdistと記述します。

f:id:ryonnsui1201:20181224230147p:plain

環境変数の設定

最後に環境変数の設定です。
.envに設定したContentfulのSpace ID,Access Token,Post Type IDを設定する必要があるので設定します。 f:id:ryonnsui1201:20181224232042p:plain

サイトの公開

以上までで、設定は完了です。 Netlify上で、「Deploy Site」をクリックすることでサイトが公開されます。

まとめ

Nuxt+Contentful+Netlifyという構成で簡単にSPAサイトを作成することができました。 初学者でも非常に簡単に作成できるので非常にオススメの構成です。

今後は、現在作成途中のバンドHPを最後まで作り切ると共に Contentful,Netlifyで出来ることに関してもっと理解を深めていきたいと考えています。

さいごに

現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。

興味のある方は、是非下記からご応募お願い致します!

www.wantedly.com

www.wantedly.com

www.wantedly.com