Help us understand the problem. What is going on with this article?

【前編】GridsomeとContentfulを使って、簡単に更新できる静的LPページを作ってみる

diffeasyアドベントカレンダー16日目の記事です。

最近開発しているアプリケーションのLPサイトを作るのに、お知らせ機能を作りたいという話がでていました。
ただ、お知らせ機能を追加するにあたって、

  • LPサイトは静的で書き出したい(SEO対策とかで)
  • アプリケーションAPI側にトピックスやブログコンテンツを持ちたくない
  • だからといって、Wordpressはサーバー運用だったりバージョンアップデート等で今後の辛みもあるから個人的に使いたくない

ということで、静的サイトジェネレーター&Headless CMSを使ってみました!

やっていくこと

  1. フロントをGridsomeで作る
  2. Contentfulでお知らせ内容を書く
  3. Github Actionsを使って更新を検知し、Firebase Hostingに自動デプロイする

です!

ホスティング先が、なぜよくHeadless CMSを使うときによく勧められてるNetlifyではなくFirebase Hositngかというと、単に自分が使い慣れているというのと、あんまりFirebase Hostingで使ってるって記事を見かけなかったので使ってみました。

また、書いている途中で膨大な量になりそうだなと思ったので【前編】と【後編】に分けることにしました!

  • 前編ではContentfulとGridsomeを使ってローカルで動きを確認するところまで
  • 後編ではFirebase Hostingにデプロイ&Github Actionsでのデプロイの設定

を書いていこうと思います💪

Gridsomeとは

GridsomeはVue.js製の静的サイトジェネレーターで、

  • いろんなCMSと繋ぐためのプラグインがある
  • GraphQLを使ってデータ成型できる
  • Vue製なので、Vueに慣れてたら結構簡単に扱える

ことができます。

ちなみに、React製の静的サイトジェネレーターにGatsby.jsというのがあるのですが、GridsomeはGatsby.jsを参考にして作られたそうです。

また、弊社ではフロントエンドにNuxt.jsを採用しているので、Generateしたら静的吐き出しできるし、これでいいじゃんって思うかもしれないですが、新しいものを使いたかったっていうのと、データをGraph QLで整形できるのめちゃんこ便利じゃんって思ったので、今回使ってみました。

Contentful

ContentfulはHeadless CMSの話題が出てきたときから結構有名どころ(だと思ってる)のCMSです。
英語版しかないですが、一回設定したら基本はコンテンツを追加するだけなのでそんなに困らないかなと思います(英語の勉強にもなるし)。

英語慣れしていない人でも更新できるよう、日本製Headless CMSのmicroCMSとも迷ったのですが、WebhookがmicroCMSだとSlack or Netlifyに対して、ContentfulだとTravisCIやCircleCIなどにも飛ばせるほか、カスタムWebhookを作成できるので、設定次第で色んなことができそうなContentfulを選びました。

Contentfulのセットアップ

Content modelを作成する

Contentfulでは、お知らせページやブログの内容を構成する情報のことをContent modelと言います。
まずはContentfulにログインし、Content modelタブに移動します。

スクリーンショット 2019-12-15 17.32.12.png

次に、「Add content type」を選択し、Content modelを作っていきます。
ここで注意すべき点は、下の画像のように、名前は英語で入力してください。
Gridsome側のプラグインで読み込む際、Nameが日本語だと読み込めません。

スクリーンショット 2019-12-15 17.33.17.png

次に、サイドバーにある「Add field」を選択し、お知らせページを構成する要素を追加していきます。
内容(Articles)については、Rich Text or Textが選択できると思いますが、僕はTextLong textを選択することをおすすめします。
理由は

  1. Long textだとMarkdownで書けるから
  2. Rich Textだとコードブロックが置けない?(自分が分かってないだけかも…)
  3. Rich Textは公式が@contentful/rich-text-html-rendererを提供しているけど、コードをまとめれなかったり(一行ずつに分割される)、Vueだと拡張が結構大変に感じた

からです。
Rich Textも全然悪くはないと思うし、Wordpressで慣れてる人とかはこっちのほうがいいって人もいるかもなので、今後のアップデートには期待しています🎉

スクリーンショット 2019-12-15 17.42.23.png

設定し終わったら、右上のsaveを押して保存してください。

投稿する

次に、お知らせの投稿を1つしておきましょう。
Content modelタブの右横にあるContentタブから投稿を追加できます。
内容を書き終わったら、サイドバーにあるPublishボタンを押して、公開状態にしましょう!

スクリーンショット 2019-12-15 23.02.58.png

APIキーを作成する

最後に、Gridsome側でコンテンツを取得する際に必要となるAPIキーを作成します。
SettingsタブからAPI keysを選択し、次の画面でAdd API keyを選択します。

スクリーンショット 2019-12-15 23.06.11.png

ここのNameは好きな名前をつけてください。
必要になるのは、Space IDContentful Delivery API - access tokenの2つです。
次にやるGridsomeの設定で使うので、画面をそのままにするか、どこかにコピーしておいてください。

スクリーンショット 2019-12-15 23.08.18.png

Gridsomeのセットアップ

必要なものをインストールする

$ npm i -g @gridsome/cli
$ gridsome create lp-site && cd $_
$ npm i @gridsome/source-contentful markdown-it

Contentful pluginの設定

プロジェクトルートにあるgridsome.config.jsを編集します。
公式に載っているものそのままですがYOUR_SPACEの部分にさっき出したSpace IDを、YOUR_ACCESS_TOKENの部分にaccess_tokenを置きます。
しかし、そのまま置くと環境ごとに分けられなかったり、Githubのpublicリポジトリなんかにpushしたときには全世界の人に見られたりするのでenvファイルに書いて読み込ませたりしたいと思います。

幸いなことに、Gridsomeではdotenvを使って対応しています
また、Gridsomeでは.env.productionまたは.env.developmentをルートディレクトリに配置することで、環境別の変数を用意できます。最高ですね!

gridsome.config.js
module.exports = {
  plugins: [
    {
      use: '@gridsome/source-contentful',
      options: {
        space: process.env.CONTENTFUL_SPACE_ID,
        accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
        host: 'cdn.contentful.com',
        environment: 'master',
        typeName: 'Contentful'
      }
    }
  ]
}
.env
CONTENTFUL_SPACE_ID=YOUR_SPACE
CONTENTFUL_ACCESS_TOKEN=YOUR_ACCESS_TOKEN

GraphQL explorerでデータ構造をチェックする

Gridsomeをdevelopで起動すると、GraphQL explorerを開けるようになります。
これを使えば、Gridsomeを起動した時点でContentfulから情報を取得してきて、その構造を確認することができます。

表示方法は、npm run developコマンドを打つと下のような表示が出てくるので、ブラウザでhttp://localhost:8080/___exploreを開くだけです!

$ npm run develop

  Site running at:                                         
  - Local:                 http://localhost:8080/          
  - Network:               http://192.168.1.86:8080/       

  Explore GraphQL data at: http://localhost:8080/___explore

するとこんな画面が開かれると思います

スクリーンショット 2019-12-16 1.17.20.png

これは、GraphQLのクエリを試しに打ってみて実行して確認ができる画面になります。
使えるクエリを見るには、右側のDOCSタブをクリックしてみるといいです。

スクリーンショット 2019-12-16 1.22.37.png

実行できるクエリたちが並んでいるので、それを左側の画面に入力して再生ボタンをクリックすれば動かすことができます!
このエディタ上だと入力補完が効くので、すごく便利です✨

試しに、一覧情報を取得するクエリを書いてみます。
コードは上画像の構造を元に書いていくので、分からなかったら照らし合わせてみてください!

# queryには自由な名前を定義できます
#(主に再生ボタンを押したときに、どのクエリを実行するかに使用したりします)
query getAllTopics {
  allContentfulTopics {
    edges {
      node {
        id
        title
        article
        createdAt
        updatedAt
      }
    }
  }
}

書けたら、真ん中の再生ボタンを押して、実行してみてください。
Contentfulの設定のときに書いた内容が取得できていると思います!(こうなれば成功です)

スクリーンショット 2019-12-16 1.25.48.png

まずは一覧ページを作ってみる

Contentfulから情報を取得できていることが確認できたので、ページを作っていきましょう。
ページの作り方は、Nuxt.jsを使っている人は親近感が湧く作り方になると思いますが、pagesディレクトリ内に作っていきます。

まずは、お知らせページの一覧画面を作ってみましょう!

$ touch src/pages/Topics.vue
src/pages/Topics.vue
<template>
  <Layout>
    <h1>Topics</h1>
    <ul>
      <li v-for="topics in $page.allTopics.edges" :key="topics.node.id">
        <g-link :to="`/topics/${topics.node.id}`">{{ topics.node.title }}</g-link>
      </li>
    </ul>
  </Layout>
</template>

<page-query>
query getAllTopics {
  allTopics: allContentfulTopics {
    edges {
      node {
        id
        title
      }
    }
  }
}
</page-query>

ちょっと独特な書き方をしていますが、分解すると

  • src/main.jsに書いてありますが、Layoutコンポーネントがグローバルコンポーネントとして登録されています。これは全体的なレイアウトを統一するために存在しています
  • GraphQLクエリは<page-query>タグで囲って記述します。この中に先程書いたクエリを転記します
  • allContentfulTopicsクエリの前にallTopicsと書いてありますが、これはコンポーネント内でクエリの実行結果を使うときの名前です。つけない場合はallContentfulTopicsの名前で取り扱います
  • page-queryでの実行結果をコンポーネント内で使うときはthis.$pageを使います。ここに実行結果が入ってきます

という感じになります。

詳細ページを作ってみる

次に詳細ページを作っていきましょう。
詳細ページを作るときはカスタムルートを作る必要があるので、pagesディレクトリにファイルを置くだけでは作れません。
カスタムルートの作り方は

  1. gridsome.config.jsにカスタムルートを作成する
  2. src/templatesに、設定したカスタムルートに訪問した時表示するコンポーネントを作成する

という流れになります。

まずはgridsome.config.jsに下を追記します。

gridsome.config.js
module.exports = {
  plugins: [
    ...
  ],
  // ここから追記
  templates: {
    // ここは "Contentful + Content model名" になる
    ContentfulTopics: [
      {
        path: '/topics/:id',
        component: './src/templates/TheTopics.vue',
      },
    ],
  },
}

次に、src/templatesTheTopics.vueを作り、追記します。

TheTopics.vue
<template>
  <Layout>
    <h1>{{ $page.topics.title }}</h1>
    <main>
      <div v-html="article"></div>
    </main>
  </Layout>
</template>

<page-query>
  query topics($id: ID!) {
    topics: contentfulTopics(id: $id) {
      title
      article
    }
  }
</page-query>

<script>
import markdownIt from 'markdown-it'
export default {
  computed: {
    article() {
      const md = new markdownIt()
      return md.render(this.$page.topics.article)
    }
  }
}
</script>

ここでは以下の動きをしています

  • queryの$idでカスタムルートに指定した/:idの値を取得し、ID型で定義します。それを使ってcontentfulTopics(id: $id)でコンテンツの指定を行います。
  • articleはMarkdownを使っているので、Markdown parser(今回はmarkdown-itを使っています)を使ってHTMLに変換し、v-htmlに流しています

ここでnpm run developをして/topicsからリンクを踏めば、詳細画面が開けることが確認できると思います!やったね!

このようにして、フロント側を作っていきます。
もっと詳しいことを学習されたい方は、ぜひ公式ドキュメントを!
少し前と比べたらドキュメント量も増えてて、デザインも新しくなって見やすくなったので、一通りわかればサクサク進められると思います✨

前編はここまでです。最後まで見てくださり、ありがとうございます!

前編の終わりに

いかがでしたか?
ちょっと癖がありますが、慣れたら結構簡単に画面を作っていけるので、個人的にはGridsomeおすすめです!

後編は12月23日のアドベントカレンダーで書きたいと思っているので、よかったら見てください😆

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした