Nuxt.jsのSSGで、ページの生成時にAPIリクエストを減らす方法はありますか?

nuxt.config.jsのgenerateプロパティにroutesのオプションを設定することで、ページのリクエストを減少させることが可能です。

今回は一例として、記事一覧ページと記事詳細ページがあるページを想定し、記事詳細ページにてAPIリクエストを減少させる方法を説明します。

ページのリクエスト減少させるサンプル

ページリクエストを減少させるためのサンプルコードをご紹介します。
今回は、大量に存在するslugのコンポーネントでasyncData()を利用し、APIからデータを取得していくようなケースを想定します。
その場合、SSG時にコンポーネントの数の分だけAPIアクセスしてページを生成していくことになります。

しかしながら、まず一箇所で集中してデータを取得し、取得したデータをそれぞれのコンポーネントに配布していく方法を取ることで、対象のAPIアクセスを削減できる場合がありより効率的になります。
例えば、記事一覧ページと記事詳細ページを作成するようなケースを想定します。ファイル構成やソースコードは以下のように作成したとします。

記事一覧ページ
<template>
    <div>
        <nuxt-link
            v-for="topic in topics"
            :key="topic.topics_id"
            :to="`/topics/${topic.topics_id}`"
        >
            {{ topic.subject }}
        </nuxt-link>
    </div>
</template>

<script>
// TopicsList page
// /pages/topics/index.vue
export default {
    async asyncData ({ $axios }) {
        return { topics: (await $axios.$get(`${process.env.BASE_URL}/rcms-api/1/topics/`)).list }
    }
}
</script>
記事詳細ページ
<template>
    <div>
        <h1 class="title">{{ topic.subject }}</h1>
        <div class="post" v-html="topic.contents"></div>
    </div>
</template>

<script>
// TopicsDetail page
// /pages/topics/_slug.vue
export default {
    // calls 100 times on static generation if the topics contains 100 items
    async asyncData ({ $axios, params }) {
        return { topic: (await $axios.$get(`${process.env.BASE_URL}/rcms-api/1/topicsdetail/${params.slug}`)).details }
    }
}
</script>

上記ソースコードでは、仮に100件の記事が存在する時には100回分の記事詳細APIへのリクエストがされます。
しかしながら、実際には記事詳細はtitlecontentsしか利用していません。
この場合、これらデータは記事一覧で取得したデータ内に含まれているため、そもそも記事詳細のAPIをリクエストする必要がありません。

routesのオプションを設定し、ページのリクエストを減少させる

より効率的にするため、記事一覧用データを1回だけ取得し、そのデータを各コンポーネントへと配備していくよう修正します。

nuxt.configの修正

まずはnuxt.config.jsを修正します。以下のように修正してください。

nuxt.config.js
require('dotenv').config();
const { BASE_URL } = process.env;
import axios from 'axios';

module.exports = {
  generate: {
    async routes() {
      const topicsList = (await axios.get(`${process.env.BASE_URL}/rcms-api/1/topics`)).data.list;
      return topicsList.map((topic) => ({
        route: `/topics/${topic.topics_id}`,  // a path of TopicsDetail
        payload: topic  // destributes topic data to the target component (TopicsDetail)
      }))
    }
  },

記事詳細ページの修正

次に、記事詳細ページを以下のように修正します。

記事詳細ページ
<template>
    <div>
        <h1 class="title">{{ topic.subject }}</h1>
        <div class="post" v-html="topic.contents"></div>
    </div>
</template>

<script>
// TopicsDetail page
// /pages/topics/_slug.vue
export default {
-    async asyncData ({ $axios, params }) {
-        // calls 100 times on static generation if the topics contains 100 items
+    async asyncData ({ $axios, params, payload }) {
+        // conveys the topic data as `payload`
+        if (payload) {
+            return { topic: payload };
+        }
+        // now that we don't use bellow any longer on static generation, but remain it just in case of local dev
        return { topic: (await $axios.$get(`${process.env.BASE_URL}/rcms-api/1/topicsdetail/${params.slug}`)).details }
    }
}
</script>

この修正により、SSGにおける記事詳細ページではリクエストが0回となり、100回分の記事詳細へのリクエストがされないようになりました。
そのため、結果的にSSGによる記事生成処理が短縮されることになります。

ローカルで確認する際は、ターミナル上でnpx nuxt generate && npx nuxt serveを実行してください。

nuxt.config.jsのrouteについては、Nuxt公式ドキュメント -> routesについてをご参照ください。

お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。