Async Components - 必要時にコンポーネントを遅延ロードする
ロードマップ: Vue.js学習ロードマップ
What(何についてか)
Async Components は、コンポーネントを初回ロード時にまとめて読み込まず、必要になった時にだけ遅延ロードする仕組みである。
Vue では defineAsyncComponent() を使って、Promise ベースでコンポーネントを読み込む wrapper component を定義できる。
Why(なぜ必要か)
大きなアプリケーションでは、すべてのコンポーネントを初回表示時にまとめてバンドルへ含めると、初期ロードが重くなりやすい。
特に以下のような部品は、初回表示に不要であることが多い。
- 管理者ページ
- モーダルの中身
- 重いグラフやリッチエディタ
- 非アクティブなタブの内容
- 条件付きでしか表示されない設定画面
このような部品を必要時まで遅延ロードすることで、初期表示コストを下げられる。
How(どう動くか)
1. Basic Usage
defineAsyncComponent() に loader function を渡す。
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)実務では、手書きの Promise よりも ES modules の dynamic import を使うのが一般的である。
この AsyncComp は wrapper component であり、実際に render されるタイミングで初めて loader が実行される。
flowchart LR A["Parent renders AsyncComp"] --> B["loader runs"] B --> C["chunk loaded"] C --> D["inner component rendered"]
2. props / slots は透過的に渡る
Async component wrapper は、受け取った props と slots を内部コンポーネントへそのまま渡す。 したがって、利用側は通常のコンポーネントとほぼ同じ API で扱える。
3. global / local / script setup どこでも定義可能
app.component()による global registrationcomponentsoption による local registration<script setup>内での直接定義
いずれでも使える。
Loading and Error States
非同期処理には loading と error が伴うため、defineAsyncComponent() では詳細オプションを指定できる。
const AsyncComp = defineAsyncComponent({
loader: () => import('./Foo.vue'),
loadingComponent: LoadingComponent,
delay: 200,
errorComponent: ErrorComponent,
timeout: 3000
})loadingComponent
読み込み中に表示する placeholder component。 spinner や skeleton の表示に使う。
delay
loadingComponent を表示するまでの待機時間。デフォルトは 200ms。 短時間のロードで loading UI が一瞬だけ点滅する flicker を防ぐためにある。
errorComponent
loader が reject した時に表示する component。 chunk load failure やネットワーク失敗時の UX を受け持つ。
timeout
一定時間を超えた場合に errorComponent を表示させるための閾値。デフォルトは Infinity。
実務での採用判断
Async Components は「常に使うべき標準設計」ではなく、必要な箇所へ適用するパフォーマンス最適化である。
async に向くケース
- 初回表示に不要
- 部品が重い
- アクセス頻度が低い
- 遅れて出ても UX 的に自然
async に向かないケース
- ファーストビューで必ず必要
- 軽量な共通部品
- 直後にほぼ確実に使われる主要 UI
実務ルール
- ページの主役は通常 import を優先
- 後から出る重い脇役は async 候補
- まず素直に作り、ボトルネックが見えたら計測して最適化する
Lazy Hydration
この節は SSR 利用時のみ意味を持つ。
SSR では、サーバーが返した HTML をクライアント側で Vue component として有効化する hydration が必要になる。 Lazy Hydration は、その hydration を即時ではなく条件付きで遅延させる仕組みである。
built-in strategies
hydrateOnIdle(): ブラウザが暇な時に hydratehydrateOnVisible(): 表示領域に入った時に hydratehydrateOnMediaQuery(): media query 条件成立時に hydratehydrateOnInteraction(): interaction 発生時に hydrate
import { defineAsyncComponent, hydrateOnVisible } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})Async Components が「コードをいつ読むか」の制御であるのに対し、Lazy Hydration は「SSR 後の UI をいつ起動するか」の制御である。
Using with Suspense
Async Components は <Suspense> と併用できる。
- 個別 component 単位の loading / error 制御は Async Components
- 複数の非同期依存をまとめて待つ制御は Suspense
という役割分担で理解するとよい。
パフォーマンス最適化との向き合い方
Async Components は有効な最適化手段だが、早すぎる最適化は複雑さを増やす。
現実的な進め方は以下である。
- まず素直に実装する
- 重そうな部品だけ lazy load 候補として意識する
- 実測してボトルネックを確認する
- 問題が確認できた箇所だけ最適化する
Options API → Composition API 差分(補足)
| 項目 | Options API(旧) | Composition API(新) |
|---|---|---|
| async component 定義場所 | components option 内に書くことが多い | <script setup> で局所的に定義しやすい |
| ロジックの見通し | registration と周辺設定が option に分散しやすい | import と定義が近く、 lazy load 意図が見えやすい |
| SSR との連携 | 利用可能だが抽象度が高い | Vue 3.5+ の hydration strategy と組み合わせやすい |
Key Concepts
| 用語 | 説明 |
|---|---|
| defineAsyncComponent | 非同期コンポーネント wrapper を定義する API |
| dynamic import | Promise を返す ES modules の遅延 import |
| loadingComponent | 読み込み中に表示する component |
| errorComponent | 読み込み失敗時に表示する component |
| delay | loading UI の flicker を避けるための待機時間 |
| timeout | 長時間待機時に失敗扱いへ切り替える閾値 |
| lazy hydration | SSR 後の hydrate 実行タイミングを遅延する最適化 |
| Suspense | 複数の非同期依存をまとめて待つ built-in component |