Nuxt.jsでGatsbyJS的なことができるnuxt/contentを試してみる

# GatsbyJSとは？

GatsbyJSとは、React製の静的サイトジェネレーターです。

- UIはReactで構築
- データは `article.md` のようなマークダウンで作る
- ビルドすることで、トップページ・タグアーカイブ・記事個別ページなどなど必要なファイルを `.html` で生成する

こんなことができます。
静的HTMLファイルなので、Netlify / AWS Amplify Console / Firebase Hosting等にデプロイすれば非常に低コストで運用できます。
データベース等も使わないので、万が一急にアクセスが増えても、先述のようなホスティングサービスを利用していればまず問題なく捌けます。

以前ポートフォリオサイトとブログをGatsbyJSで作ってみましたが、データの取得にGraphQLを使う部分や、各ページを生成するロジックを実装するあたりでかなりてこずってしまい、「できればNuxt.jsでやりたいなー」と思っていました。

# nuxt/contentが出た！

2020/5/24にnuxt/contentがバージョン1.0.0を迎えました！
https://github.com/nuxt/content

本家サイト（ https://content.nuxtjs.org/ ）も非常にシンプルでわかりやすく、簡単にサンプルを組み立てることができました。
内容としてはまさに欲しかったものです！

# 使ってみる

- yarnをインストールする（省略）
- Nuxt.jsプロジェクトを作成する

```bash
# プロジェクトを作成
$ yarn create nuxt-app nuxt-content-blog

# オプションは全てデフォルトにしました
? Project name nuxt-content-blog
? Project description My tiptop Nuxt.js project
? Author name tetsushi
? Choose programming language JavaScript
? Choose the package manager Yarn
? Choose UI framework None
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Choose linting tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Choose test framework None
? Choose rendering mode Universal (SSR)
? Choose development tools (Press <space> to select, <a> to toggle all, <i> to invert selection)

# ディレクトリを移動
$ cd nuxt-content-blog

# ローカルサーバーを起動
$ yarn dev
```

`http://localhost:3000/` にアクセスすると以下のようないつもの画面が表示されます。

<img width="1219" alt="スクリーンショット 2020-06-02 08.42.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142803/cd6ef6fd-dba9-bb8c-24e4-7ae122a5ce6e.png">

- nuxt/contentをインストールする

公式ドキュメントに沿って進めればハマるところはありませんでした。
https://content.nuxtjs.org/installation

```bash
$ yarn add @nuxt/content
```

- `nuxt.config.js` を調整する

```javascript
{
  modules: [
    '@nuxt/content' // これを追加
  ],
}
```

これであっさり準備完了です。
ディレクトリ構造はこのようになりました。

```bash
$ tree -I node_modules
.
├── README.md
├── assets
│   └── README.md
├── components
│   ├── Logo.vue
│   └── README.md
├── layouts
│   ├── README.md
│   └── default.vue
├── middleware
│   └── README.md
├── nuxt.config.js
├── package.json
├── pages
│   ├── README.md
│   └── index.vue
├── plugins
│   └── README.md
├── static
│   ├── README.md
│   └── favicon.ico
├── store
│   └── README.md
└── yarn.lock
```

# 記事ファイルを置いてみる

ブログを作るイメージで、記事を書いてみます。
`content/articles` というディレクトリを作り、 `article-1.md` と `article-2.md` を作成しました。

```bash
$ tree content/
content/
└── articles
    ├── article-1.md
    └── article-2.md
```

`content/articles/article-1.md` の内容は以下です。

```markdown:content/articles/article-1.md
---
title: 記事1
tags: [Nuxt.js JavaScript]
---

# 見出し1

## 見出し2

本文本文
```

`content/articles/article-2.md` にも同じような内容を書きました。
これで記事は準備完了です。

# 一覧ページを作ってみる

ブログのトップページをイメージして、記事一覧を出力してみます。
トップページ（`/`）にページを作るので、 `pages/index.vue` を作成します。

```vue:pages/index.vue
<template>
  <div>
    <div v-for="article in articles">
      <nuxt-link :to="article.path">{{ article.title }}</nuxt-link>
    </div>
  </div>
</template>

<script>
export default {
  components: {},
  async asyncData({ $content }) {
    const articles = await $content("articles")
      .limit(5)
      .fetch();

    return {
      articles
    };
  }
};
</script>
```

`asyncData` 関数でクエリを組み立てます。
クエリはLokiJSというインメモリデータベースライブラリで組み立てます。
https://github.com/techfort/LokiJS

これだけのコードであっという間に素朴なトップページが出来上がってしまいました。

<img width="1223" alt="スクリーンショット 2020-06-02 08.54.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142803/95104b8f-3cea-4aef-a4ba-e232af889248.png">

リンク先は `article.path` としています。 
`content/articles/article-1.md` というファイルを作ったので、デフォルトではこの投稿のパスは `/articles/article-1` となります。

記事個別ページのテンプレートはまだないので、クリックしてもエラーになります。
では、次に記事個別ページを作ります。

# 記事個別ページを作る

記事個別ページは `/articles/{slug}` にします。
`pages/articles/_slug.vue` を作成しました。

```vue:pages/articles/_slug.vue
<template>
  <div class="container">
    {{ article.title }}

    <nuxt-content :document="article" />
  </div>
</template>

<script>
export default {
  components: {},
  async asyncData({ $content, params }) {
    const article = await $content(`articles/${params.slug}`).fetch();

    return {
      article
    };
  }
};
</script>
```

これで個別ページも完成です。

<img width="1223" alt="スクリーンショット 2020-06-02 08.57.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142803/c5f35602-553e-a01f-fee6-3e85546df3fa.png">

# まとめ

記事の配列を得る方法と、単一の記事を得る方法をまず調べました。
これさえあればあとはタグアーカイブを作ったり、ページネーションを作ったりすることはさほど苦労しないかと思います。

見た目を整えるのは普通のVue.js / Nuxt.jsの開発と同じようにコンポーネントを作ってやっていけそうです。

普段はAngularで開発していますが、React / VueのHMRは非常に便利です。
ブログ執筆等では、なんならWordPress等のCMSよりも書きやすいかもしれません。

コンテンツがDBではなくGitで管理できるのも魅力的です。
必要な実装方法を調べ終わったらどんどんGatsbyJSから乗り換えて行こうかと思います。