Full Static Generationを試す

Nuxt.jsの Full Static Generationとは Nuxt 2.13で導入された 
**APIレスポンスも合わせてすべて静的化する**ための機能です。

今回はnpm packageのjson-serverをつかってモックapiを作成して、
APIの値を取得して静的書き出しをするところまでやってみます。 
(` Nuxt @ v2.14.9 `で試しています)


## API側の準備
### jsonを用意
```json:db.json
{
  "news": [
    {
      "id": "title_001",
      "body": "Hello World"
    },
    {
      "id": "title_002",
      "body": "おはようございます"
    },
    {
      "id": "title_003",
      "body": "こんにちは"
    },
    {
      "id": "title_004",
      "body": "おやすみ"
    }
  ]
}
```
### コマンドの追加
package.json に
`npm run api_server`というコマンドを追加します。

```json:package.json
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "api_server" : "node_modules/.bin/json-server --watch db.json --port 3333"
  }
```


## Nuxtの準備

#### nuxt.config.jsの設定
はじめにnuxt.config.jsを
generateモードに設定するためにtargetをstaticにします。

```js:nuxt.config.js
  target :"static",
```


#### 今回のFile構成
```
-| pages/
---| index.vue
---| news/
-----| _slug.vue
```

Nuxt v2.13から generate時に内部的にクローリング処理が行われ、
リンク先を自動的に検出してページ生成を行われるようになりました。

たとえばnews/index.vueを作成して

```vue:news/index.vue
<template>
  <div class="container">
    <ul>
      <li v-for="item in news">
        <nuxt-link :to="`/news/${item.id}`">
          {{item.body}}
        </nuxt-link>
      </li>
    </ul>
    </div>
</template>

<script>
export default {
  async asyncData ({ params}) {
    return axios.get('http://localhost:3333/news').then((res) => {
      return {news : res.data}
    }).catch((error) => {
      return { error: error }
    })
  }
}
</script>
```
このようなファイルを用意して`npm run generate`をたたくと
APIから取得したデータと`<nuxt-link>`から動的に静的ファイルが生成されます。
（Nuxt v2.13以降）

今回はリンクされていないページを想定し
_slug.vueにAPIにあるidの値を元に動的にファイルを生成させることにします。


#### nuxt.config.jsにAPIを取得するコードを追加

```js:nuxt.config.js
  generate: {
    routes () {
      return axios.get('http://localhost:3333/news')
        .then((res) => {
          return res.data.map((news) => {
            return {
              route: '/news/' + news.id,
              payload: news
            }
          })
        })
    }
  }
```
generate routesで使われるのがAPIのレスポンスデータのnews.idを使ってのものだけだと
_sulg.vue側で都度取得することになってしまい生成時間の増加につながってしまうらしく、
そういう場合はpayloadを設定して（今回でいうとAPIのデータ "id","body"をpaylodで渡せる）、動的ルーティング生成の高速化をおこなうようです。

### _sulg.vue側のコード
動的に表示する_sulg.vueは下記の様に設定します。

```vue:_sulg.vue
<template>
  <div class="container">
    <div>
        <p>title : {{id}}</p>
        <p>content : {{body}}</p>
    </div>
    </div>
</template>


<script>
import axios from "axios";

export default {
  data () {
    return {
      id:"",
      body:""
    }
  },
  async asyncData ({ params, error, payload }) {
    if (payload) {
      return {
        id: payload.id,
        body: payload.body,
      }
    } else {
      return axios.get('http://localhost:3333/news').then((res) => {
        return res.data.find((post) => post.id === params.slug);
      }).catch((error) => {
        return { error: error }
      })
    }
  }
}
</script>
```
 `npm run dev`で開発できるように
payloadの条件分岐をわけています。


#### generate
この状態で
1.json-server を立ち上げ

```
npm run api_server
```
2.generateする

```
npm run generate
```
APIの情報を取り込みファイルを書き出せました。

```
-| dist/
---| index.html
---| news/
-----| title_001/
-------| index.html
-----| title_002/
-------| index.html
...略

```

news/title_001/index.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3093/1f6bdb0d-3253-b914-5bad-a93d1aebd324.png)

無事APIレスポンスを取り込んで書き出すことができました。
今回はAPIの部分をjson-serverを使ったモックで済ませましたが本来 [strapi+nuxt.jsでアドベントカレンダーを作ろう](/sunnyplace/items/c3f16ad9ca6adb4c9b75)のようにHeadless CMSからのAPIを取得から生成を試して見たかったのですが、それはまたどこかで。



---
[:christmas_tree: FORK Advent Calendar 2020](/advent-calendar/2020/fork)
:arrow_left: 15日目 [前の日の記事のタイトル](/yoh_zzzz/items/28683dc3fc38b0ace4ec) @yoh_zzzz
:arrow_right: 17日目 [次の日の記事のタイトル](/sy12345/items/d36cc281f6a037cd4b7a) @sy12345