MeWrite Docs

ChunkLoadError: Loading chunk failed

Webpackのコード分割で動的チャンクの読み込みに失敗した際のエラー

概要

ChunkLoadError: Loading chunk failed は、Webpackのコード分割(Code Splitting)機能で生成された動的チャンクファイルの読み込みに失敗した際に発生するエラーです。デプロイ後のキャッシュ不整合が最も一般的な原因で、ユーザーが古いHTMLを保持したまま新しいチャンクを要求すると発生します。

エラーメッセージ

ChunkLoadError: Loading chunk 123 failed.
(error: https://example.com/static/js/123.abc123.js)
Uncaught (in promise) ChunkLoadError: Loading chunk vendors~main failed.
Loading CSS chunk mini-css-extract-plugin failed.

原因

  1. デプロイ後のキャッシュ不整合: 古いHTMLが新しいチャンクファイル名を知らない、または古いファイルがCDNから削除されている
  2. CDN/ネットワークの問題: チャンクファイルの配信が一時的に失敗している
  3. publicPathの設定ミス: チャンクファイルのURLが正しく解決されない
  4. アドブロッカーによるブロック: 特定のチャンクファイル名がブロックリストに該当
  5. S3/CloudFrontのキャッシュ: 古いファイルがエッジキャッシュに残っている

解決策

1. 動的importにリトライロジックを追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// リトライ付きの動的import関数
function retryImport<T>(
  importFn: () => Promise<T>,
  retries = 3,
  delay = 1000
): Promise<T> {
  return new Promise((resolve, reject) => {
    importFn()
      .then(resolve)
      .catch((error) => {
        if (retries <= 0) {
          reject(error);
          return;
        }
        setTimeout(() => {
          retryImport(importFn, retries - 1, delay * 2).then(resolve, reject);
        }, delay);
      });
  });
}

// 使用例
const LazyComponent = React.lazy(() =>
  retryImport(() => import("./HeavyComponent"))
);

2. Reactエラーバウンダリでフォールバック

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class ChunkErrorBoundary extends React.Component<
  { children: React.ReactNode },
  { hasError: boolean }
> {
  constructor(props: { children: React.ReactNode }) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: Error) {
    if (error.name === "ChunkLoadError") {
      return { hasError: true };
    }
    throw error;
  }

  handleReload = () => {
    window.location.reload();
  };

  render() {
    if (this.state.hasError) {
      return (
        <div>
          <p>新しいバージョンが利用可能です。</p>
          <button onClick={this.handleReload}>ページを再読み込み</button>
        </div>
      );
    }
    return this.props.children;
  }
}

3. Webpack設定でファイル名にcontentHashを使用

1
2
3
4
5
6
7
8
9
// webpack.config.js
module.exports = {
  output: {
    filename: "[name].[contenthash].js",
    chunkFilename: "[name].[contenthash].js",
    publicPath: "/",
    clean: true, // ビルド前に出力ディレクトリをクリーン
  },
};

4. Service Workerでキャッシュ管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// service-worker.js
self.addEventListener("install", (event) => {
  // 新しいService Workerをすぐにアクティブにする
  self.skipWaiting();
});

self.addEventListener("activate", (event) => {
  // 古いキャッシュを削除
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames
          .filter((name) => name !== CURRENT_CACHE_VERSION)
          .map((name) => caches.delete(name))
      );
    })
  );
});

5. Next.jsでの対応

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// next.config.js
module.exports = {
  // チャンクロードエラー時の自動リロード
  onDemandEntries: {
    maxInactiveAge: 25 * 1000,
    pagesBufferLength: 2,
  },
};

// _app.tsxでグローバルエラーハンドリング
if (typeof window !== "undefined") {
  window.addEventListener("error", (event) => {
    if (
      event.message?.includes("Loading chunk") ||
      event.message?.includes("ChunkLoadError")
    ) {
      window.location.reload();
    }
  });
}

関連エラー

JavaScript の他のエラー

最終更新: 2026-02-03