Nuxt/Content で Markdown なブログ・お知らせサイト作る

Nuxt 3 / Nuxt Content 2.9 向けの更新記事を以下に記載しましたのでこちらも参考になさってください。↓

https://zenn.dev/feb19/articles/b05c5b1d290163

---


Yo 我らすぐブログ作るけど中身更新しなーい

# 三行

- [@Nuxt/Content](https://content.nuxtjs.org/) ってやつの `v1.0.0` が公開された
- Nuxt.js で Markdown ブログとかニュースページを作るのが死ぬほど簡単になった
- Markdown ファイルとか JSON から Nuxt.js へ受け渡しをいい感じにやってくれるモジュールだよ

# 作ってみよう

## package.json と nuxt.config.js を準備

```json:package.json
{
  ...
  "scripts": {
    "dev": "nuxt",
    "generate": "nuxt generate"
  },
  "dependencies": {
    "@nuxt/content": "^1.0.0",
    "nuxt": "^2.12.2"
  }
}
```

```js:nuxt.config.js
  ...
  modules: [
    '@nuxt/content'
  ],
```

## レポジトリ構造

content ディレクトリを作って、 md ファイルを入れます。
pages ディレクトリに news ディレクトリを切って、ここに詳細ページと一覧を表示します。

```
% tree . -N
.
├── content
│   └── news
│       ├── 20200526.md
│       └── 20200527.md
├── layouts
│   └── default.vue
├── node_modules
├── nuxt.config.js
├── package-lock.json
├── package.json
├── pages
│   ├── index.vue
│   └── news
│       ├── _slug.vue
│       └── index.vue
└── static
    └── images
        └── news
            ├── sample26.png
            └── sample27.png
```

## 一覧に表示: content ディレクトリから md を拾ってくる

```vue:news/index.vue
<template>
  <div>
    <div v-for="n in news" :key="n.slug">
      <nuxt-link :to="'/news/'+ n.slug">{{n.title}} {{n.date}}</nuxt-link>
    </div>
  </div>
</template>

<script>

export default {
  async asyncData ({ $content, params }) {
    const query = await $content('news' || 'index').limit(15)
    const news = await query.fetch()
    return { news }
  }
}
</script>
```

## 詳細を表示: content ディレクトリから md を拾ってくる

```vue:news/_slug.vue
<template>
  <article>
    <h1>{{news.title}}</h1>
    <dl>
      <dt>date</dt>
      <dd>{{news.date}}</dd>
    </dl>
    <div><img :src="news.image" /></div>
    <div v-for="tag in news.tags" :key="tag">{{tag}}</div>
    
    <nuxt-content :document="news" />
  </article>
</template>

<script>
export default {
  async asyncData ({ $content, params }) {
    const news = await $content('news', params.slug || 'index').fetch()
    return { news }
  }
}
</script>
```

実際に実行してみて、起動できるかチェック

```
% npm run dev

localhost:3000
```


## 生成もしてみる

以下 generate を nuxt.config.js に追加しておこう (今最新の Nuxt 2.12 までは)

```js:nuxt.config.js
  generate: {
    // Nuxt 2.13+ では、これすらいらなくくなるらしい（すごい）
    async routes () {
      const { $content } = require('@nuxt/content')
      const files = await $content('news' || 'index').fetch()

      return files.map(file => file.path === '/index' ? '/' : file.path)
    }
  }
  ```

```zsh
% npm run generate

> nuxt-content-web@1.0.0 generate /Users/takahashi.nobuhiro/git/web/nuxt-content-web
> nuxt generate

Entrypoint app = server.js
ℹ Generating pages                                                               14:00:07
✔ Generated /news/20200526                                                       14:00:07
✔ Generated /news                                                                14:00:07
✔ Generated /                                                                    14:00:07
✔ Generated /news/20200527                                                       14:00:07
```

動的なファイルも SSG される

## 上記サンプルソースコード

https://github.com/feb19/nuxt-content-web

# ほかなにができるの

- Vue Component を Markdown に埋めるとかできる
  - [MDX](https://mdxjs.com/) みがある
  - Twitter Component 作って埋め込めたり nuxt-link とか書けるのでいいね
- Markdown のホットリロードとかも用意されて快適
- テキスト検索とかも用意されている
- シンタックスハイライトも実装済み
- Hooks 構造体を追加して、カスタムアクションとかも追加できる
    - 例えばこの例だと、Markdown ファイルを解析して、「読了時間」を追加するっていうのができる  
      https://content.nuxtjs.org/advanced#hooks

# かんそう

- GitHub ベースの Headless CMS アーキテクチャなサイトにめっちゃ良さそう
- いろんな人が Markdown 書けるようになって git の基礎的な操作ができるようになったらいいなぁ

[個人サイト](https://feb19.jp)も先日このスタックで作り直しました。