WP REST APIを元にNuxt.jsのgenerateで記事ページを自動生成してみる(いわゆる動的ルーティング)

せっかくREST APIの情報を元にページを作るならgenerateするファイルは自動で出力したいですよね。
公式ドキュメントのところでいう「動的ルーティング」を使って実現してみましょう。
うまくいけばREST APIを元に自動でディレクトリ構造やhtmlファイルが生成されます。

考え方

nuxt.config.jsにgenerateプロパティを記述、そこに使用するAPI情報を読み込む記述をします。
ここでは読み込んだjsonの配列の中にある、ディレクトリ構造を示す値をrouteに設定していきます。

次に自動生成されるページ用のテンプレートファイルを作成します。
ディレクトリに対して細かく設定することも出来ますがWPのパーマリンクを元にする事を考えると「pages/_.vue」というファイルを作ってしまうのが手っ取り早いかなと思います。
テンプレートファイルは頭文字にアンダースコアを付けるのがNuxtの仕様ですが、その中でも「_.vue」は指定のないルーティング全てに適用されていきます。
必要に応じて「pages/category/_id.vue」とか作っていけば良いかなと思います。

まとめると、
・ディレクトリを自動生成する為のnuxt.config.jsの設定
・vueファイルにREST APIから受け取った記事ごとの詳細情報を当てはめ出力
この二段階となります。

設定が必要なファイルだけディレクトリ構造を書いておくとこんな感じになります。

pages/
 - _.vue
 - index.vue
nuxt.config.js

このpages/_.vueを元に下記のようなファイルが出力されれば成功です。

dist/
 - archives/
   - 101/
     - index.html
   - 102/
     - index.html
   - 103/
     - index.html
 - index.html

nuxt.config.jsの書き方

generateプロパティに入れる値は、手動で書くとroutesに対してパス情報の配列を入れていくという形になります。

export default {
  generate: {
    routes: [
      '/post/1',
      '/post/2',
      '/post/3'
    ]
  }
}

この形を、WP REST APIの情報を元に記述するのは下記の様な記述になります。

ちなみにgenerateする時はmodeがspaじゃ上手く動きません。必ずuniversalにしましょう。
それとAPIをGETする為にaxiosをインポートしておきましょう。

import axios from 'axios'
export default {
  mode: 'universal', // modeはuniversalに。

  generate: {
    routes () {
      // ちなみにREST APIの仕様で全件取得は出来ません(最大100件)。
      // 一度に全件生成したい場合はREST API側をカスタマイズする必要があります。
      return axios.get('https://test.com/wp-json/wp/v2/posts/?per_page=100')
      	.then((res) => {
      	  // map()メソッドでパーマリンクの情報をrouteに渡します。
          return res.data.map((post) => {
	      	// パーマリンクの文字列をディレクトリ生成用に加工します。
            const str = post.link;
            const _link = str.replace( /https:\/\/test.com/g , "" );
            post.link = _link;

            return {
              route: post.link,  // ここに入る文字列がパス情報になる。
              payload: post,     // テンプレートで値を受け取れるようデータをpayloadへ。
            }
          })
        })
    }
  }
}

ここがきちんと動けば、とりあえずそれだけでディレクトリは自動生成されます。
データを受け取って出力するには次のvueファイルを用意します。

vueファイルの書き方

vueファイルの方はそんなに難しいことはしません。asyncDataメソッドを使ってpayloadから必要なデータを受け取ってビューに反映するだけです。
payloadからデータを受け取れなかった場合の分岐も書いたほうが無難ではありますが、今回はgenerateして静的ファイルにしてしまうので割愛します。

<template>
	<div class="container">
	  <h1>{{title}}</h1>
	  <h2>{{dir}}</h2>
	</div>
</template>
<script>
export default {
  data () {
    return {
      // 記事ページで使うデータを格納する為の変数を定義していきます。
      title: '',
      dir: ''
    }
  },
  async asyncData ({ store, params, error, payload }) {
    // payloadからデータを受け取ったらそこから値を変数へ入れます。
    if (payload) {
      return {
        // ここでどんな値にアクセスするかはREST APIで返ってくるjson構造を参照
        title: payload.title.rendered,
        dir: payload.link
      }
    }
  }
}
</script>

これでWPのパーマリンクを元にしたディレクトリ構造と静的ファイルが生成されるはずです。
実際に記事ページとして成り立たせるにはvueファイルの方で更にデータの受け取りや反映が必要ですが、その辺はそれぞれの必要に応じて記述していくとこかと思います。

僕自身はこれで一番ハマったのはmodeをuniversalにするのを忘れていたという悲しくなる凡ミスでしたが、どなたかの参考になれば幸いです。

Nuxt.jsビギナーズガイド