Nuxt.jsのSSGを使用してAPIコール回数を削減できますか?
Nuxt 3でAPIコール回数を削減する方法
概要
Nuxt 3でSSG(静的サイト生成)を使用する際、多数のページを生成するとAPIリクエストが増加し、ビルド時間やコストに影響することがあります。この記事では、事前にデータを一括取得することで、APIコール回数を効率的に削減する方法を紹介します。
この方法が役立つケース
- 記事一覧と詳細ページなど、多数のページを生成する場合
- APIコール回数に制限がある場合
- ビルド時間を短縮したい場合
- サーバー負荷を軽減したい場合
解決方法
通常のSSGでは、各ページの生成時にAPIリクエストが発生します。例えば、100記事の詳細ページを生成する場合、100回のAPIリクエストが必要になります。
しかし、プリフェッチ方式を使用すると、最初に一括でデータを取得し、そのデータを使って各ページを生成できます。これにより、APIリクエスト回数を大幅に削減できます。
実装手順
1. プリフェッチの基本設定
まず、APIからデータを事前に取得するための環境を構築します。
# プリフェッチ用のディレクトリとファイルを作成
mkdir -p prefetch/data
touch prefetch/index.js
# .gitignoreにデータディレクトリを追加
echo "prefetch/data" >> .gitignore
2. プリフェッチスクリプトの作成 (prefetch/index.js)
次に、APIからデータを取得して保存するスクリプトを作成します。以下のコードを prefetch/index.js
ファイルに保存します。
// prefetch/index.js
import fs from 'fs/promises';
import path from 'path';
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
// 環境変数の読み込み
dotenv.config();
const ROOT_URL = process.env.NUXT_PUBLIC_API_BASE;
// ファイルパスの設定
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const EXPORT_PATH = path.join(__dirname, 'data');
// 取得対象のAPIエンドポイント一覧
const ALL_LIST_ENDPOINTS = ['/rcms-api/1/example/list'];
// エクスポート先ディレクトリの作成
const createExportPath = async () => {
try {
await fs.access(EXPORT_PATH);
} catch (error) {
await fs.mkdir(EXPORT_PATH, { recursive: true });
}
};
// APIデータを取得する関数
async function kurocoAPIAll(endpoint) {
// 最初のページを取得
const initialData = await fetch(`${ROOT_URL}${endpoint}`).then(res => res.json());
const { list, pageInfo } = initialData;
const totalPageCnt = pageInfo.totalPageCnt;
// 2ページ目以降を並列で取得
const promises = [];
for (let i = 2; i <= totalPageCnt; i++) {
promises.push(
fetch(`${ROOT_URL}${endpoint}?pageID=${i}`).then(res => res.json())
);
}
const allData = await Promise.all(promises);
const allList = allData.map((data) => data.list).flat();
// 全てのデータを結合
return [...list, ...allList];
}
// メイン処理
(async () => {
console.log('データのプリフェッチを開始します');
await createExportPath();
// 全てのエンドポイントからデータを取得して保存
for (const endpoint of ALL_LIST_ENDPOINTS) {
const data = await kurocoAPIAll(endpoint);
const fileName = endpoint.replaceAll('/', '_');
const filePath = path.join(EXPORT_PATH, `all${fileName}.json`);
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
console.log(`データを保存しました: ${filePath}`);
}
console.log('全てのデータのプリフェッチが完了しました');
})();
3. package.jsonにスクリプトを追加
プリフェッチを簡単に実行できるようにするため、package.jsonにスクリプトを追加します。
"scripts": {
"prefetch": "node prefetch/index.js"
}
4. 一覧ページの実装
プリフェッチしたデータを使用して、一覧ページを実装します。
<template>
<ul>
<li v-for="item in listJSON" :key="item.topics_id">
<NuxtLink :to="`/ssg_list/${item.topics_id}`">{{ item.subject }}</NuxtLink>
</li>
</ul>
</template>
<script lang="ts" setup>
// プリフェッチしたJSONファイルを読み込む
const { data: listJSON } = await useAsyncData('filteredList', async () => {
const fullListJSON = await import('~/prefetch/data/all_rcms-api_1_example_list.json')
.then((m) => m.default);
// 必要なプロパティのみを抽出(データ量削減)
return fullListJSON.map((item: any) => ({
topics_id: item.topics_id,
subject: item.subject
}));
});
</script>
5. 詳細ページの実装
同様に、詳細ページもプリフェッチしたデータを使用して実装します。
<template>
<template v-if="item">
<h1>
<span>{{ item.subject }}</span>
</h1>
<section v-if="item.content">
<div v-for="(content, idx) in item.content" :key="idx"
v-html="content.content_wysiwyg"></div>
</section>
</template>
<NuxtLink to="/ssg_list">戻る</NuxtLink>
</template>
<script lang="ts" setup>
const { topics_id } = useRoute().params;
// プリフェッチしたJSONファイルから該当データを検索
const { data: item } = await useAsyncData(`filteredList-${topics_id}`, async () => {
const fullListJSON = await import('~/prefetch/data/all_rcms-api_1_example_list.json')
.then((m) => m.default);
// IDに一致するアイテムを検索
return fullListJSON
.map((item: any) => ({
topics_id: item.topics_id,
subject: item.subject,
content: item.content
}))
.find((item) => `${item.topics_id}` === topics_id);
});
// アイテムが見つからない場合は404エラーを表示
if (!item) {
throw createError({
statusCode: 404,
statusMessage: 'Not Found'
});
}
</script>
6. SSGの実行
最後に、プリフェッチとSSGを実行します。
# データのプリフェッチを実行
npm run prefetch
# 静的サイトを生成
npm run generate
想定通りの静的ファイル生成が確認できたらYAMLファイルを調整してnpm run generate の前にnpm run prefetchを実行するステップを追加してください。(KurocoFrontでデプロイする場合)
メリットと注意点
メリット
- APIコール削減: 多数のページを生成する場合でも、APIコール回数を大幅に削減できます
- 高速な表示: 事前に生成されたHTMLとJSONを使用するため、ページ表示が高速です
- SEO対策: 静的HTMLが生成されるため、検索エンジンのクローラーに適しています
- コスト削減: APIコール回数の削減により、APIサービスの利用料金を削減できます
注意点
- データの鮮度: プリフェッチしたデータは静的なため、最新の情報を反映するには定期的に再ビルドする必要があります
- ビルド時間: データ量が多い場合、プリフェッチとビルドに時間がかかる場合があります
- 動的コンテンツ: ユーザー固有のデータなど、完全に動的なコンテンツには適していません
まとめ
Nuxt 3のSSGでAPIコール回数を削減するには、プリフェッチ方式が効果的です。この方法を使うことで、多数のページを効率的に生成しながら、APIコール回数を最小限に抑えることができます。特に大規模なサイトや、APIコール回数に制限がある場合に有効な手法です。
サポート
お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。