Nuxtコンテンツでブログを作成するtutorialをやってみた

## **Nuxtコンテンツでブログを作成する**
以下のtutorialを参考にNuxtのcontentモジュールの学習を進めてみたのでやったこと学んだことをアウトプットしてみる。

https://nuxtjs.org/ja/tutorials/creating-blog-with-nuxt-content

ローカルでnodejs環境を作るのが久しぶりでnodebrewのセットアップ時にハマった。

https://qiita.com/hmaruyama/items/e6d5d3d7b7d095591c47

Nuxtプロジェクト作成
`npx create-nuxt-app nuxt-project-sample`
上記の記事に合わせるために以下の問いにはヘッドレスCMSを選択する

```json
? Project name: nuxt-project-sample
? Programming language: JavaScript
? Package manager: Npm
? UI framework: None
? Nuxt.js modules: Content - Git-based headless CMS
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? What is your GitHub username? kensukeueno
? Version control system: Git
```

## コンテンツモジュールは`content/`ディレクトリ内のファイルを読み取る。

markdown、csv、yaml、json、json5、またはxmlを解析できるらしい。

## フロントマター内の画像は静的フォルダーにないといけない。

> 記事のYAMLに含まれる画像をレンダリングするには、画像を静的フォルダーに配置するか、構文を使用する必要があります。**[@ nuxt / content](https://github.com/nuxt/content)**は独立し`:src="require(`~/assets/images/${article.img}`)"`ているため、記事のコンテンツに含まれる画像は常に**静的フォルダー**に配置する必要があります。 Webpack。静的フォルダーはwebpackを通過しませんが、assetsフォルダーは通過します。
> 

## **NuxtLinkタグとは？**

Vuejsの`router-link`を拡張しているもの。
`<a>`は**外部ページ**、`<NuxtLink>`は**内部ページ**という使い分け方をする。
また`<NuxtLink>`はパフォーマンスを高めるのに有効らしい。

https://qiita.com/sonimaru/items/0f8c22542f026a535cf2#%E3%81%98%E3%82%83%E3%81%82%E6%98%8E%E7%A2%BA%E3%81%AB%E4%BD%95%E3%81%8C%E9%81%95%E3%81%86%E3%81%AE

## h2,h3タグのリンク等はtoc変数で取得できる

これをループさせるだけでリンクが作成できる。（ここではarticleページ内のtocを取得している）

```jsx
/* toc変数にはh2,h3のみが格納される */
/* articleはページ情報 */
<li v-for="link of article.toc" :key="link.id">
    <NuxtLink :to="`#${link.id}`">{{ link.text }}</NuxtLink>
</li>
```

## Componentを使用する

nuxt.config.jsに以下の設定することでcomponentがグローバルに使えるようになる。

```json
export default {
  components: true
}
```

## 呼び出したComponentはtemplateタグで上書きできる

component以下
templateタグを設置せずにComponentを呼び出した場合はComponent内のtemplateがデフォルトで呼び出される。

InfoBox.vue (component)

```jsx
<template>
  <div class="p-4 mb-4 text-white bg-blue-500">
    <p><slot name="info-box">default</slot></p>
  </div>
</template>
```

markdown(呼び出し先)

```jsx
<info-box>
  <template #info-box>
    <!-- template内を上書きできる。templateがなければデフォルトのComponentの値が表示される -->
    This is a vue component inside markdown using slots
  </template>
</info-box>
```

## mdやxmlファイル等にコードブロックを埋め込む

Content モジュールでは、Prism の自動インクルージョンによりCodeブロックをカンマ3つが囲えば自動で作成してくれるようになっている。以下のようにすればいい。

 ```
(```)
<p>code styling is easy</p>
(```)
 ```

## NuxtLinkで動的にlink先を指定する。（`to` → `:to` にする）
リンク先を変数名にしたいだとかってときは以下のように`:to`を使ってあげればいい
```markdown
<NuxtLink
      v-if="prev"
      :to="{ name: 'blog-slug', params: { slug: prev.slug } }"
    >
```

## asyncDataとは？

asyncDataの引数はContextオブジェクトの分割代入
contentオブジェクトやurlを受け取れたりする。ほかにもいろいろ受け取れるので気になったら調べる感じでいい。

```jsx
const contextObject = { $content: ~, params: ~ }

async asyncData({ $content, params }) {
  const article = await $content('articles', params.slug).fetch()
  return { article, prev, next }
}
```

## 記事に対してAPI経由で情報を取得する

content/以下のxml等のファイルの場所を、以下のようにcontentにアンダーバー(_)をつけて取得できる。（以下ローカルでのAPI取得用URL）

**[http://localhost:3000/_content/~](http://localhost:3000/_content/)** 

## 記事を取得するAPIをwhereクエリで絞り込む

以下のようなURLのパラメータを使って記事の著者名と一致した人のみ取得できるようにする。

**[http：// localhost：3000 / _content / articles？author.name = Maria](http://localhost:3000/_content/articles?author.name=Maria)**

まずは、next.config.jsに以下のような記述が必要

```jsx
export default {
  content: {
    nestedProperties: ['author.name']
  }
}
```

そして以下のように`author.name`をwhereで指定すればいい。

```jsx
async asyncData({ $content, params }) {
      const articles = await $content('articles', params.slug)
        .where({
          'author.name': {
            $regex: [params.author, 'i']
          }
        })
        .fetch()

      return {
        articles
      }
}
```

## onlyメソッドとwithoutメソッド

上記で使ってきた$contentはグローバルなインスタンスであり様々なメソッドを持つ。

例えばonly()やwithoutもそのひとつである。

$content.onlyメソッドは引数の記事情報のみを抽出する。抽出したい情報が少ない場合に使うといい。

https://content.nuxtjs.org/ja/fetching#onlykeys

$content.withoutメソッドは引数の記事情報を除外する。抽出したい情報が多いときに使うといい。

https://content.nuxtjs.org/ja/fetching#withoutkeys

## watchメソッドで検索できるようにする

watchメソッドは基本的に[ プロパティ:データ ] のように定義するが、関数を指定することもできる。以下のようにすることで`searchQuery`に変更があったかどうかとwatchで監視できる。

また、searchQueryプロパティを検索フォームと双方向バインディングさせることで`searchQuery`　

に経由で処理を走らせる事ができる。
```javascript
data() {
      return {
        searchQuery: ''
      }
    },
watch: {
      async searchQuery(searchQuery) {
        if (!searchQuery) {
          this.articles = []
          return
        }
        this.articles = await this.$content('articles')
          .limit(6)
          .search(searchQuery)
          .fetch()
      }
```