Skip to content

遅延読み込み

12.3.1. ルートレベルのコード分割

  • すべてのルートコンポーネントは動的 import() を使用して遅延読み込みします。
  • 静的 import でルートコンポーネントを読み込むことは許可しません。
  • 動的 import() を使用すると Vite が自動的にルートごとのチャンクを生成します。
typescript
// 正しい例: 動的 import
{
  path: '/dashboard',
  name: 'Dashboard',
  component: () => import('@/views/DashboardView.vue'),
  meta: { title: 'ダッシュボード', requiresAuth: true },
}

// 誤った例: 静的 import(使用禁止)
import DashboardView from '@/views/DashboardView.vue'
{
  path: '/dashboard',
  name: 'Dashboard',
  component: DashboardView,
}
  • 例外として、常にレンダリングされる最上位レイアウトコンポーネントは静的 import を許可します。

12.3.2. ローディング状態の処理

  • 遅延読み込み中にユーザーにローディング状態を表示しなければなりません。
  • defineAsyncComponent を使用してローディングコンポーネントとエラーコンポーネントを指定します。
  • ネットワーク遅延が短い場合にローディング画面がちらつくのを防止するため delay オプションを設定します。
typescript
import { defineAsyncComponent } from 'vue'
import LoadingSpinner from '@/components/common/LoadingSpinner.vue'
import ErrorFallback from '@/components/common/ErrorFallback.vue'

const AsyncDashboard = defineAsyncComponent({
  loader: () => import('@/views/DashboardView.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorFallback,
  delay: 200,
  timeout: 10000,
})
オプション説明デフォルト値
loaderコンポーネントを返す関数必須
loadingComponentローディング中に表示するコンポーネントなし
errorComponent読み込み失敗時に表示するコンポーネントなし
delayローディングコンポーネントの表示遅延時間(ms)200
timeoutタイムアウト時間(ms)無制限

12.3.3. プリロード戦略

  • ユーザーエクスペリエンスを向上させるため、次のページのチャンクを事前に読み込む戦略を適用します。
  • 3つのプリロード方式のうち、プロジェクトの特性に合った方式を選択します。

リンクホバー時のプリロード

vue
<script setup lang="ts">
function preloadRoute(importFn: () => Promise<unknown>) {
  importFn()
}
</script>

<template>
  <RouterLink
    :to="{ name: 'UserList' }"
    @mouseenter="preloadRoute(() => import('@/views/user/UserListView.vue'))"
  >
    ユーザー一覧
  </RouterLink>
</template>

ビューポート進入時のプリロード

typescript
// src/composables/useRoutePreload.ts
import { useIntersectionObserver } from '@vueuse/core'
import type { Ref } from 'vue'

export function useRoutePreload(
  target: Ref<HTMLElement | null>,
  importFn: () => Promise<unknown>
) {
  let loaded = false

  useIntersectionObserver(target, ([entry]) => {
    if (entry.isIntersecting && !loaded) {
      loaded = true
      importFn()
    }
  })
}

HTML link タグによるプリフェッチ

  • Vite はビルド時に <link rel="modulepreload"> を自動的に挿入します。
  • 追加のプリフェッチが必要な場合は vite-plugin-preload などのプラグインを使用します。

12.3.4. チャンクネーミング

  • Vite 環境では rollupOptions.output.chunkFileNames を使用してチャンク名のパターンを設定します。
  • デバッグとバンドル分析のために意味のあるチャンク名を付与します。
typescript
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js',
        assetFileNames: 'assets/[name]-[hash].[ext]',
        manualChunks: {
          'vendor-vue': ['vue', 'vue-router', 'pinia'],
        },
      },
    },
  },
})
項目規則
ルートコンポーネント動的 import() 必須
ローディングコンポーネントdefineAsyncComponent で指定
プリロードホバーまたはビューポート進入方式を適用
チャンクネーミングrollupOptions でパターンを設定
ベンダー分離manualChunks で共通ライブラリを分離

TIENIPIA QUALIFIED STANDARD