vue.js
nuxt.js
contentful
Vue.js #3Day 21

Nuxt.jsとContentfulでブログ作ってみた

これは Vue.js #3 Advent Calendar 2017 – Qiita 21日目の記事です。

nuxt_ctf.jpg


Nuxt.js 使ってみたいけど何をつくろうかな〜と思案していたらば、『SEO、OGP……Vue.js製SPAの「困った」を解決できる「Nuxt.js」が便利だ!』という記事でブログを作っていたので、なんだかちょうどよさそうと思い以下を追加してやってみることにしました。

  1. Contentful から記事を取得する
  2. トップページに配置するコンポーネント( components/PostPreview.vue )をつくる
  3. 記事一覧ページと個別記事ページをつくる
  4. nuxt generate で静的ファイルを生成する
  5. GitHub Pages にデプロイ

Nuxt.js ってどんなもんじゃ?という方の参考になれば幸いです :upside_down:

0. とりあえず準備

0-1. Contentful にアカウントを作ったり

Contentful:ドイツのスタートアップ Contentful が開発した、 API に焦点を当てたコンテンツ管理システム(CMS)

以下の記事を参考にして、

以下までを終わらせる。

  • アカウント作成
  • スペース作成
  • Content Delivery API キー作成
  • API キーを .contentful.json に設定

0-2. Nuxtのアプリケーションのベースのセットアップをしたり

SEO、OGP……Vue.js製SPAの「困った」を解決できる「Nuxt.js」が便利だ!』の以下までをちまちまとやって、アプリケーションの大枠を作る。

  1. 「アプリケーションのセットアップと設定」
  2. 「ページレイアウトの操作」
  3. 「ブログのTOPページを作成する」
  4. 「Aboutページの作成」

0-3. 必要なパッケージを追加インストールしたりすると

npm install --save contentful
npm install --save vue-markdown
npm install --save-dev push-dir

0-4. こんなディレクトリになっているのではないかな...?

-| .nuxt/
-| components/
-| layouts/
-| middleware/(今回は使わない)
-| node_modules/
-| pages/
---| about.vue
---| index.vue
-| plugins/
---| contentful.js
-| static/
-| store/(今回は使わない)
-| .contentful.json
-| .editorconfig
-| .eslintrc.js
-| .gitignore
-| nuxt.config.js
-| package.json
-| README.md

1. Contentful から記事を取得する

pages/index.vue で非同期データを取得します。

pages/index.vue
asyncData ({ env }) {
  return client.getEntries({
    'content_type': env.CTF_BLOG_POST_TYPE_ID,
    order: '-fields.publishDate',
    'limit': 3
  }).then(entries => {
    return {
      posts: entries.items
    }
  }).catch(console.error)
}

:hushed: へ〜、 Nuxt.js には asyncData メソッドっていうのがあるのね。
https://ja.nuxtjs.org/guide/async-data

2. トップページに配置するコンポーネント(components/PostPreview.vue)をつくる

pages/index.vue で取得した非同期データをコンポーネントに渡します。

pages/index.vue
<PostPreview :posts="posts"></PostPreview>
components/PostPreview.vue
export default {
  props: ['posts']
}

:rolling_eyes: あ、 asyncData メソッドはページコンポーネントだけで、普通(?)のコンポーネントは持たないのね...。
https://ja.nuxtjs.org/faq/async-data-components/

3. 記事一覧ページと個別記事ページをつくる

Nuxt.js は pages/ ディレクトリ内の Vue ファイルの木構造に沿って、自動的に vue-router の設定を生成してくれます。

記事一覧ページのURLは https://xxxxxxx/posts/ としたいので、 pages/ 配下に posts/ ディレクトリを切り、インデックスのページコンポーネントをつくります。
個別記事ページはContentfulから取得したslugで動的にルーティングしたいので、 アンダーバーをつけたページコンポーネント _slug.vue をつくります。

-| pages/
---| posts/
-----| index.vue // 記事一覧ページ
-----| _slug.vue // 個別記事ページ
---| about.vue
---| index.vue
.nuxt/router.js
routes: [
{
  path: "/",
  component: _5512af1c,
  name: "index"
},
{
  path: "/posts",
  component: _4aea9340,
  name: "posts"
},
{
  path: "/about",
  component: _355ad457,
  name: "about"
},
{
  path: "/posts/:slug",
  component: _4e57d5d0,
  name: "posts-slug"
}
]

:relaxed: 便利...!!
https://ja.nuxtjs.org/guide/routing/

各ページコンポーネントで、非同期データを取得、取得データの表示などをなんやかやします。
個別記事ページへのリンクはなんとなく名前付きルートにしました。

pages/posts/index.vue
<nuxt-link :to="{ name: 'posts-slug', params: { slug: post.fields.slug }}" class="card-footer-item">
  Read More
</nuxt-link>

https://ja.nuxtjs.org/api/components-nuxt-link
https://router.vuejs.org/ja/api/router-link.html

4. nuxt generate で静的ファイルを生成する

何もしないと nuxt generate で生成されるのはルート/ だけです。
そのため、 vue-router で path: "/posts/:slug" と動的に定義されているルーティングを、 generate プロパティの routes にも設定します。

nuxt.config.js
generate: {
  routes () {
    return client.getEntries({
        'content_type': config.CTF_BLOG_POST_TYPE_ID
      }).then((entries) => {
      return [...entries.items.map(entry => `posts/${entry.fields.slug}`)]
    })
  }
},

:neutral_face: 動的なパラメータのときは Promise を返す関数。
https://ja.nuxtjs.org/api/configuration-generate

5. GitHub Pagesにデプロイ

デプロイ用の scripts を追加しましょう。

package.json
"scripts": {
  "dev": "nuxt",
  "build": "nuxt build",
  "start": "nuxt start",
  "generate": "nuxt generate",
  "deploy": "push-dir --dir=dist --branch=gh-pages --cleanup" //これ
},

:slight_smile: GitHub Pages へデプロイするには? https://ja.nuxtjs.org/faq/github-pages

今回はプロジェクトリポジトリにデプロイするので、アプリケーションのベース URL としてリポジトリ名を設定します。

nuxt.config.js
router: {
  base: '/nuxt_blog/'
},

:hushed: この設定をしないと
こうなってほしいのが → https://hisako135.github.io/nuxt_blog/posts
こうなってしまう → https://hisako135.github.io/posts

そして以下コマンドをポチーーーー :point_down_tone2:

npm run generate
npm run deploy

完成

Nuxt.js を初めて使ってみて個人的に「あ、そうなんだ...!」となったことを抜粋しているのでだいぶ端折っていたりあまりエレガントでない部分もありますが、もうちょっとこの子を育てていきたいです2018年。

参考にさせていただいたもの