13
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

FORKAdvent Calendar 2020

Day 16

Full Static Generationを試す

Last updated at Posted at 2020-12-15

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

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

API側の準備

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というコマンドを追加します。

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にします。

nuxt.config.js
  target :"static",

今回のFile構成

-| pages/
---| index.vue
---| news/
-----| _slug.vue

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

たとえばnews/index.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を取得するコードを追加

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は下記の様に設定します。

_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

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


:christmas_tree: FORK Advent Calendar 2020
:arrow_left: 15日目 前の日の記事のタイトル @yoh_zzzz
:arrow_right: 17日目 次の日の記事のタイトル @sy12345

13
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?