async-components について
必要になった時点でコンポーネントを読み込む方法を解説する Vue 開発向けスキルです。大きなコンポーネントや条件付き表示の遅延読み込みと、ローディング・エラー状態の設定を扱います。
主な機能
- 01コンポーネントのオンデマンド読み込み
- 02defineAsyncComponent() と動的 import()
- 03ローディング・エラーコンポーネント
- 04遅延とタイムアウトの制御
活用シーン
- 01モーダルを開く時点での読み込み
- 02条件付き表示 UI の読み込み
- 03大きなコンポーネントバンドルの分割
- 04読み込み中の状態表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill async-componentsインストール後、Claude Code で/async-componentsを入力して読み込まれたか確認します。
詳細
非同期コンポーネント
目次
大規模なウェブアプリケーションを開発する際、パフォーマンスは最優先事項です。ページの読み込み速度やインタラクティブな要素の応答性は、ユーザーエクスペリエンスに大きな影響を与えます。ウェブアプリケーションの規模と複雑さが増すにつれて、大きなコードバンドルを必要なときだけ読み込むことが重要になる場合があります。そこで役立つのが、Vue の非同期コンポーネントです。
コンポーネントは、UI を構築するための基本的な構成要素です。通常、コンポーネントを使用すると、すぐには必要でない場合でも、自動的に読み込まれて解析されます。
使用する場面
- コンポーネントのバンドルサイズが大きく、初回ページ読み込み時には必要ない場合に使用します
- モーダルやダイアログなど、ユーザーの操作に応じて条件付きでレンダリングされる UI に便利です
使用しない場面
- 非同期読み込みのオーバーヘッド(チャンクのリクエストや解析)が、バンドルサイズの削減効果を上回る小さなコンポーネント
- 初回レンダリング時に常に表示されるコンポーネント — 非同期読み込みによって表示が遅れます
- コンポーネントがすでにメインチャンクに含まれており、分割してもバンドルサイズを大幅に削減できない場合
手順
defineAsyncComponent()と動的なimport()を使用して、必要に応じてコンポーネントを読み込みます- ユーザーエクスペリエンスを向上させるため、
loadingComponentオプションとerrorComponentオプションを指定します v-ifと組み合わせて、コンポーネントが実際に必要になったときだけ非同期読み込みを開始しますdelayオプションとtimeoutオプションを使用して、読み込み動作を細かく制御します
詳細
一方、非同期コンポーネントを使うと、必要になったとき、または特定の条件を満たしたときだけ読み込まれて解析されるように、コンポーネントを定義できます。
親コンポーネントのボタンをクリックするとレンダリングされる、シンプルなモーダルコンポーネントを想定します。Modal.vue コンポーネントファイルには、モーダルの表示方法を定めるテンプレートとスタイルだけが含まれています。
<template>
<div class="modal-mask">
<div class="modal-container">
<div class="modal-body">
<h3>This is the modal!</h3>
</div>
<div class="modal-footer">
<button class="modal-default-button" @click="$emit('close')">OK</button>
</div>
</div>
</div>
</template>
親の App コンポーネントでは、モーダルコンポーネントとボタンをレンダリングできます。このボタンをクリックすると、リアクティブなブール値(showModal)を使ってモーダルコンポーネントの表示を切り替えます。
<template>
<button id="show-modal" @click="showModal = true">Show Modal</button>
<Modal v-if="showModal" :show="showModal" @close="showModal = false" />
</template>
<script setup>
import { ref } from "vue";
import Modal from "./components/Modal.vue";
const showModal = ref(false);
</script>
この例からわかるように、モーダルコンポーネントは、ユーザーが Show Modal ボタンをクリックしたときという特定の状況でのみ表示されます。それにもかかわらず、このコンポーネントに関連付けられた JavaScript バンドルは、モーダルが表示される前であっても、ウェブページ全体の読み込み時に自動的に読み込まれます。
多くの場合、これは問題ありません。しかし、モーダルのバンドルサイズが非常に大きい場合や、アプリケーションにこのようなコンポーネントが多数ある場合は、初回読み込み時間が遅くなる可能性があります。使用頻度の低いコンポーネントに関連するものでも、バンドルが追加されるたびに、初回ページの読み込みにかかる時間は長くなります。
defineAsyncComponent
ここでは、defineAsyncComponent()関数を使ってコンポーネントを非同期に読み込むことで、アプリを小さなチャンクに分割できます。
import { defineAsyncComponent } from "vue";
const AsyncComp = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
// ...load component from the server
resolve(/* loaded component */);
});
});
defineAsyncComponent()関数は、インポートしたコンポーネントを解決する Promise を返すローダー関数を受け取ります。ただし、上記のように非同期コンポーネント関数を定義する代わりに、動的インポートを利用してECMAScriptモジュールを非同期に読み込むこともできます。
import { defineAsyncComponent } from "vue";
export const AsyncComp = defineAsyncComponent(() =>
import("./components/MyComponent.vue")
);
モーダルの例で実際に見てみましょう。AsyncModal.jsという名前の新しいファイルを作成します。
import { defineAsyncComponent } from "vue";
export const AsyncModal = defineAsyncComponent(() => import("./Modal.vue"));
親のAppコンポーネントでは、Modalコンポーネントの代わりに、非同期コンポーネントのAsyncModalをインポートして使用します。
<template>
<button id="show-modal" @click="showModal = true">Show Modal</button>
<AsyncModal v-if="showModal" :show="showModal" @close="showModal = false" />
</template>
<script setup>
import { ref } from "vue";
import { AsyncModal } from "./components/AsyncModal";
const showModal = ref(false);
</script>
この小さな変更により、モーダルコンポーネントが非同期に読み込まれるようになります。アプリケーションのウェブページを最初に読み込むとき、Modalコンポーネントのバンドルは_ページの読み込み時に自動で読み込まれなくなります_。モーダルを表示するボタンをクリックすると、モーダルコンポーネントのレンダリング時にバンドルが非同期に読み込まれます。
読み込み中およびエラー時のUI
defineAsyncComponent()を使うと、Vueではコンポーネントを非同期に読み込むだけでなく、読み込み中にユーザーへフィードバックを表示したり、発生する可能性のあるエラーに対処したりできます。
loadingComponent
コンポーネントの取得中に、ユーザーに視覚的なフィードバックを提供したい場合があります。そのために、defineAsyncComponent()にはloadingComponentオプションがあり、読み込み中に表示するコンポーネントを指定できます。
import { defineAsyncComponent } from "vue";
import Loading from "./Loading.vue";
export const AsyncModal = defineAsyncComponent({
loader: () => import("./Modal.vue"),
loadingComponent: Loading,
});
モーダルコンポーネントが非同期に読み込まれる間、ユーザーにはLoading...というメッセージが表示されます。
errorComponent
インターネット接続が不安定な場合など、非同期コンポーネントの読み込みに失敗することがあります。defineAsyncComponent()関数には、そのような状況に対処するためのerrorComponentオプションがあり、読み込みエラーが発生したときに表示するコンポーネントを指定できます。
import { defineAsyncComponent } from "vue";
import Loading from "./Loading.vue";
import Error from "./Error.vue";
export const AsyncModal = defineAsyncComponent({
loader: () => import("./Modal.vue"),
loadingComponent: Loading,
errorComponent: Error,
});
モーダルコンポーネントの読み込みに失敗すると、Errorコンポーネントのテンプレートが表示されます。
defineAsyncComponent()関数では、delay、timeout、suspensible、onError()などのオプションも利用できます。これらのオプションにより、非同期読み込みの動作やユーザーエクスペリエンスをより細かく制御できます。詳しくは、APIドキュメントを確認してください。
defineAsyncComponent()関数を使うと、必要になるまで特定のコンポーネントの読み込みを遅らせ、Vueアプリケーションの初回読み込みを扱いやすいチャンクに分割できます。コンポーネント数が多く、バンドルサイズが大きいアプリケーションでは、ページの読み込み時間とアプリケーション全体のパフォーマンスの改善に役立ちます。