モジュールの遅延読み込み

アプリケーションの初期読み込みを高速化するために、すべてのモジュールを最初から読み込むのではなく、必要になったタイミングで読み込む「遅延読み込み」が効果的です。

遅延読み込みとは

ページの初期表示に必要なコードだけを先に読み込み、その他の機能は後から読み込む手法です。

即時読み込み

すべてのモジュールを最初に読み込む。初期表示が遅くなる可能性がある。

遅延読み込み

必要なモジュールだけを必要なタイミングで読み込む。初期表示が高速化される。

動的インポートによる遅延読み込み

import() 関数を使用して、必要になった時点でモジュールを読み込みます。

// ボタンクリック時に初めてモジュールを読み込む
document.getElementById('chart-btn').addEventListener('click', async () => {
  const { Chart } = await import('./chart.js');
  const chart = new Chart('#container');
  chart.render();
});

ルートベースの遅延読み込み

SPA(Single Page Application)では、ページ遷移時に必要なコンポーネントだけを読み込むパターンが一般的です。

const routes = {
  '/': () => import('./pages/Home.js'),
  '/about': () => import('./pages/About.js'),
  '/contact': () => import('./pages/Contact.js'),
  '/dashboard': () => import('./pages/Dashboard.js')
};

async function navigate(path) {
  const loader = routes[path];
  if (loader) {
    const module = await loader();
    renderPage(module.default);
  }
}

// ナビゲーションイベントで呼び出す
window.addEventListener('popstate', () => navigate(location.pathname));

条件付き読み込み

特定の条件を満たした場合のみ、重いモジュールを読み込みます。

async function initEditor() {
  const textarea = document.querySelector('textarea');
  
  if (textarea && textarea.dataset.rich === 'true') {
    // リッチエディタが必要な場合のみ読み込む
    const { RichEditor } = await import('./RichEditor.js');
    return new RichEditor(textarea);
  }
  
  return textarea;
}

Intersection Observer との組み合わせ

要素が画面内に入ったタイミングでモジュールを読み込むパターンです。

const observer = new IntersectionObserver(async (entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      const element = entry.target;
      
      if (element.dataset.component === 'gallery') {
        const { Gallery } = await import('./Gallery.js');
        new Gallery(element);
        observer.unobserve(element);
      }
    }
  }
});

// 遅延読み込み対象の要素を監視
document.querySelectorAll('[data-lazy]').forEach(el => {
  observer.observe(el);
});

プリロードによる最適化

遅延読み込みでも、ユーザーが使いそうな機能は事前にプリロードしておくと、体験が向上します。

<!-- 後で使う可能性が高いモジュールをプリロード -->
<link rel="modulepreload" href="./Chart.js">
// マウスホバー時にプリロードを開始
document.getElementById('chart-btn').addEventListener('mouseenter', () => {
  import('./Chart.js'); // プリロード(結果は使わない)
});

document.getElementById('chart-btn').addEventListener('click', async () => {
  // キャッシュから即座に取得できる
  const { Chart } = await import('./Chart.js');
  new Chart('#container').render();
});

ローディング表示

モジュールの読み込み中は、ユーザーにフィードバックを表示しましょう。

async function loadFeature() {
  const container = document.getElementById('feature');
  container.innerHTML = '<div class="loading">読み込み中...</div>';
  
  try {
    const { Feature } = await import('./Feature.js');
    container.innerHTML = '';
    new Feature(container);
  } catch (error) {
    container.innerHTML = '<div class="error">読み込みに失敗しました</div>';
  }
}
メリット

初期読み込みの高速化、必要なリソースだけをダウンロード、帯域の節約

注意点

ネットワーク遅延による待ち時間、適切なローディング UI の必要性

遅延読み込みを適切に活用することで、大規模なアプリケーションでも高速な初期表示を実現できます。