【Nuxt.js編】Nuxt.js + Contentful + NetlifyでSPAブログを自作する

# はじめに
Nuxt.jsとContentfulとNetlifyでモダンな（？）SPAブログを作りました。[こちら](https://thinkshake.net/blog/)
何回かにわけて構築の記録を残しているシリーズの第２回です。
今回は簡単にSPAサイトが作れるフレームワーク、Nuxt.jsについて書いていきます。

【シリーズの予定】
- [まえがき編](https://qiita.com/hitsuji-haneta/items/9fb971855026386fa5c5)
- Nuxt.js編 ← この記事
- [Contentful編](https://qiita.com/hitsuji-haneta/items/6be4745b9bd6b098843f)
- [Netlify編](https://qiita.com/hitsuji-haneta/items/c6c1a9ddd74886116b72)

# 前提となる知識
[Vue.js](https://jp.vuejs.org/index.html)の基本を知っていることを前提としています。
まだやったことが無い方は[公式チュートリアル](https://jp.vuejs.org/v2/guide/)をやってみましょう。

# インストール
まずは[公式サイト](https://ja.nuxtjs.org/guide/installation#%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%83%E3%83%81%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%82%8B)に従って、インストールしていきましょう。
スクラッチからもできそうですが、スターターテンプレートでラクします。
公式サイトはnpmなのでyarnでやってみます。（yarn派なので）

```
$ yarn add -g vue-cli
$ vue init nuxt-community/starter-template nuxt_blog
 ? Project name nuxt_blog
 ? Project description <てきとうに>
 ? Author <あなたの名前>
$ cd nuxt_blog
$ yarn install
```
開発環境の起動は

```
$ yarn run dev
```
です。
[http://localhost:3000](http://localhost:3000)にアクセスして、以下のようにロゴとタイトルが表示されれば成功です。
<img width="852" alt="nuxt初期画面.png" src="https://qiita-image-store.s3.amazonaws.com/0/133447/30d8d1f0-d3b7-e4a6-a3c4-bcdd3c2e5650.png">


# テンプレートをつくる
ではテンプレートページをいじって、ブログ風にしてみましょう。
ここでは標準のHTML, CSSで書きますが、プリプロセッサを使いたい方はお好みで。(個人的にはpug＋sylusがラクで好きです。) 
こんな感じ。


```leyouts/default.vue
<template>
  <div>
    <header>
      <h1 class="title">いい感じのSPAブログ</h1>
    </header>
    <main class="container">
      <nuxt/>
    </main>
  </div>
</template>

<style>
html {
  font-family: "Source Sans Pro", 游ゴシック体, 'Yu Gothic', YuGothic, 'ヒラギノ角ゴシック Pro', 'Hiragino Kaku Gothic Pro', メイリオ, Meiryo, sans-serif;
  font-size: 16px;
}
h1, h2, h3 {
  font-weight: normal;
}
.title {
  color: #35495e;
  margin: 100px 0 30px;
  text-align: center;
}
.container {
  width: 80%;
  margin: 0 auto;
}
</style>
```

```pages/index.vue
<template>
  <section class="index">
    <card v-for="i in 5" v-bind:key="i"/>
  </section>
</template>

<script>
import Card from '~/components/card.vue'

export default {
  components: {
    Card
  }
}
</script>

<style scoped>
.index {
  display: flex;
  flex-wrap: wrap;
}
</style>
```

```pages/blog/_slug.vue
<template>
  <section class="slug">
    <h1 class="slug_title">
      タイトル
    </h1>
    <p class="slug_date">2018/8/2</p>
    <div>
      記事の内容。あああああああああああああああああああああああああああああああああああああああ
    </div>
  </section>
</template>

<style scoped>
.slug {
  max-width: 800px;
  margin: 0 auto;
}
.slug_title {
  font-size: 2.0rem;
  font-weight: bolder;
}
.slug_date {
  font-size: 1.0rem;
  color: rgb(57, 72, 85);
  text-align: right;
}
</style>
```

```components/card.vue
<template>
  <article class="card">
    <nuxt-link :to="{ name: 'blog-slug'}" class="wrapper">
      <h1 class="card_title">記事１</h1>
      <p class="card_text">記事の内容。ああああああああああああああああああ</p>
      <p class="card_date">2018/8/2</p>
    </nuxt-link>
  </article>
</template>

<style scoped>
.card {
  width: 300px;
  height: 200px;
  box-shadow: 1px 2px 3px 1px rgba(0,0,0,0.2);
  border: 0.5px solid rgb(57, 72, 85);
  padding: 10px 20px;
  margin: 10px 10px;
}
.wrapper {
  text-decoration: none;
}
.card_title {
  font-size: 1.2rem;
}
.card_text {
  color: rgb(57, 72, 85);
  margin: 10px 0;
}
.card_date {
  font-size: 0.7rem;
  color: rgb(57, 72, 85);
  text-align: right;
}
</style>
```

なんとなくブログの記事一覧っぽいのができたかと思います。

# Markdownを読み込む
記事はMarkdownで書けると便利なので、[vue-markdown](https://github.com/miaolz123/vue-markdown)を入れます。

```
$ yarn add vue-markdown
```
## vue-markdownをブログに反映する
```diff:pages/blog/_slug.vue
      <p class="slug_date">2018/8/2</p>
-     <div>
-       記事の内容。あああああああああああああああああああああああああああああああああああああああ
-     </div>
+     <vue-markdown>
+ # 記事の内容
+ - あいうえお
+   - あ
+   - い
+   - う
+   - え
+   - お
+ - かきくけこ
+ 本文本文本文本文本文本文本文本文本文
+     </vue-markdown>
    </section>
  </template>
+
+ <script>
+ import VueMarkdown from 'vue-markdown'
+ export default {
+   transition: 'slide-left',
+   components: {
+     VueMarkdown
+   }
+ }
+ </script>
```

# 無駄にアニメーションをつける
さすがに地味すぎるかなと思ったので‥

```diff:leyouts/default.vue
  .container {
    width: 80%;
    margin: 0 auto;
  }
+ .slide-left-enter {
+   transform: translateX(2000px);
+   opacity: 0;
+ }
+ .slide-left-enter-active {
+   transition: all .3s linear;
+ }
+ .slide-left-leave-to {
+   transform: translateX(-2000px);
+   opacity: 0;
+ }
+ .slide-left-leave-active {
+   transition: all .3s linear;
+ }
  </style>
```
```diff:pages/index.vue
  import Card from '~/components/card.vue'
  export default {
+   transition: 'slide-left',
    components: {
```
```diff:pages/blog/_slug.vue
  import VueMarkdown from 'vue-markdown'
  export default {
+   transition: 'slide-left',
    components: {
```

# 途中経過
画面がこんな感じになっていれば成功です！

- 記事一覧
<img width="1181" alt="記事一覧.png" src="https://qiita-image-store.s3.amazonaws.com/0/133447/9a7828fe-6881-bbe0-f848-b42454045312.png">


- 記事内容
<img width="1069" alt="記事内容.png" src="https://qiita-image-store.s3.amazonaws.com/0/133447/8d77126f-6a8b-97d0-809d-21f554f79081.png">


# 終わりに
本日はNuxt.jsで簡単にSPAブログのテンプレートを作ってみました！
ですが、記事の内容が全部同じですね。。
次回はcontentfulと連携して、記事の内容を読み込めるようにしましょう！

ではではー。