NuxtLinkのprefetchとは何か:理解と最適な設定
prefetchとは
prefetch(プリフェッチ) とは、ユーザーがリンクをクリックする前に、リンク先のデータを事前に取得しておく機能。
目的
ユーザーがリンクをクリックした時に、即座にページ遷移できるようにする。
従来の遷移:
クリック → データ取得開始 → 取得完了 → 表示
↑ この待ち時間がある
prefetchあり:
[事前にデータ取得完了] → クリック → 即座に表示
NuxtLinkのデフォルト動作
prefetchはデフォルトで有効
<!-- これは prefetch="true" と同じ -->
<NuxtLink to="/blog/article-name">記事タイトル</NuxtLink>
発動条件
リンクがビューポート(画面内)に入った時に自動的にプリフェッチが開始される。
取得されるもの
_payload.json: ページのデータ(propsなど)- JSチャンク: ページコンポーネントのJavaScript
- CSSチャンク: ページ固有のスタイル
あるべき状態
ケース1: 少数のリンク(5件以下)
prefetch有効でOK
<!-- ナビゲーションメニューなど -->
<NuxtLink to="/about">About</NuxtLink>
<NuxtLink to="/contact">Contact</NuxtLink>
理由:リクエスト数が少ないので問題にならない。
ケース2: 多数のリンク(10件以上)
prefetch無効を推奨
<!-- ブログ一覧など -->
<NuxtLink
v-for="article in articles"
:key="article.path"
:to="article.path"
:prefetch="false"
>
{{ article.title }}
</NuxtLink>
理由:大量の同時リクエストがネットワークを詰まらせる。
ケース3: 遷移確率が高いリンク
prefetch有効でOK
<!-- 「次の記事」ボタンなど -->
<NuxtLink to="/blog/next-article" prefetch>
次の記事へ
</NuxtLink>
理由:ユーザーがクリックする可能性が高い。
ケース4: 遷移確率が低いリンク
prefetch無効を推奨
<!-- フッターのリンクなど -->
<NuxtLink to="/privacy" :prefetch="false">
プライバシーポリシー
</NuxtLink>
理由:ほとんどクリックされないのに帯域を消費する。
nuxt.config.tsでのグローバル設定
prefetch戦略の変更
// nuxt.config.ts
export default defineNuxtConfig({
experimental: {
// ペイロード抽出を無効化(prefetchされるデータを減らす)
payloadExtraction: false
}
})
routeRulesで特定ルートのみ設定
export default defineNuxtConfig({
routeRules: {
// ブログ記事はprefetchしない
'/blog/**': { experimentalNoScripts: true }
}
})
今回の事例:ブログ一覧の過剰プリフェッチ
問題
/blogページから記事への遷移に約1秒のラグがあった。
原因
Chrome DevToolsで確認したところ、ページ遷移時に65個のリクエストが発生:
/blog/openai-vs-google-considerations/_payload.json
/blog/nvidia-moat/_payload.json
/blog/tax-consultation-form/_payload.json
/blog/tax-accountant-inquiry/_payload.json
/blog/drawio-viewer-test/_payload.json
/blog/blood-medicine-world/_payload.json
... 他にも多数
各リンクに対して:
_payload.json(ページデータ).css(スタイル).js(スクリプト)
が個別にリクエストされていた。
なぜ遅くなるか
- ネットワーク帯域の競合: 同時リクエストが帯域を奪い合う
- HTTP/2の同時接続制限: 同一ドメインへの同時リクエスト数に上限がある
- メインスレッドの負荷: レスポンス処理でCPUを消費
現在の実装(問題あり)
<!-- ArticleTable.vue -->
<NuxtLink :to="article.path" class="article-link">
{{ article.title }}
</NuxtLink>
<!-- BlogCalendar.vue -->
<NuxtLink :to="article.path" class="article-link">
{{ article.title }}
</NuxtLink>
両方ともprefetch未設定 → デフォルトでtrue → 過剰なプリフェッチ
修正案
<!-- ArticleTable.vue -->
<NuxtLink :to="article.path" :prefetch="false" class="article-link">
{{ article.title }}
</NuxtLink>
<!-- BlogCalendar.vue -->
<NuxtLink :to="article.path" :prefetch="false" class="article-link">
{{ article.title }}
</NuxtLink>
判断フローチャート
リンクの数は?
│
├─ 5件以下 → prefetch有効でOK
│
└─ 10件以上
│
├─ ユーザーが必ずクリックする → prefetch有効
│ (例:「次へ」ボタン)
│
└─ どれがクリックされるか不明 → prefetch無効
(例:記事一覧)
まとめ
| シチュエーション | prefetch設定 | 理由 |
|---|---|---|
| ナビゲーションメニュー | 有効(デフォルト) | リンク数が少なく、頻繁にクリックされる |
| ブログ記事一覧 | 無効 | 大量リンクで帯域を消費 |
| カレンダービュー | 無効 | 表示セルが多い(42セル) |
| 「次の記事」ボタン | 有効 | クリック確率が高い |
| フッターリンク | 無効 | クリック確率が低い |
| ページネーション | 有効/無効どちらでも | 状況による |
基本方針: 一覧ページでは:prefetch="false"を付ける習慣をつける。