From b7679cbcb1deebc94df682fcf1a44758008da9b7 Mon Sep 17 00:00:00 2001 From: hanif salafi Date: Mon, 8 Dec 2025 17:02:33 +0700 Subject: [PATCH] update bug fixing --- app/[locale]/layout.tsx | 2 + components/chunk-load-error-handler.tsx | 82 +++++++++++++++++++++++++ docs/CHUNK_LOAD_ERROR_HANDLER.md | 74 ++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 components/chunk-load-error-handler.tsx create mode 100644 docs/CHUNK_LOAD_ERROR_HANDLER.md diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 3204db83..e0987d66 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -19,6 +19,7 @@ import { NextIntlClientProvider } from "next-intl"; import { getMessages } from "next-intl/server"; import DirectionProvider from "@/providers/direction-provider"; import AuthProvider from "@/providers/auth.provider"; +import ChunkLoadErrorHandler from "@/components/chunk-load-error-handler"; export const metadata: Metadata = { title: "Media Hub | POLRI", @@ -96,6 +97,7 @@ export default async function RootLayout({ /> + diff --git a/components/chunk-load-error-handler.tsx b/components/chunk-load-error-handler.tsx new file mode 100644 index 00000000..a072da1b --- /dev/null +++ b/components/chunk-load-error-handler.tsx @@ -0,0 +1,82 @@ +"use client"; + +import { useEffect } from "react"; + +/** + * Component to handle ChunkLoadError automatically + * When a chunk fails to load (usually after deployment), + * this component will force refresh the page once + */ +export default function ChunkLoadErrorHandler() { + useEffect(() => { + // Key to track if we've already refreshed for this error + const REFRESH_KEY = "chunk-load-error-refreshed"; + + // Handle unhandled promise rejections (for dynamic imports) + const handlePromiseRejection = (event: PromiseRejectionEvent) => { + const error = event.reason; + + // Check if it's a ChunkLoadError + if ( + error?.name === "ChunkLoadError" || + error?.message?.includes("Loading chunk") || + error?.message?.includes("ChunkLoadError") || + error?.message?.includes("Failed to fetch dynamically imported module") || + error?.message?.includes("failed to load resource") + ) { + handleChunkLoadError(); + } + }; + + // Handle regular errors + const handleError = (event: ErrorEvent) => { + const error = event.error; + + // Check if it's a ChunkLoadError + if ( + error?.name === "ChunkLoadError" || + event.message?.includes("Loading chunk") || + event.message?.includes("ChunkLoadError") || + event.message?.includes("Failed to fetch dynamically imported module") + ) { + handleChunkLoadError(); + } + }; + + const handleChunkLoadError = () => { + // Check if we've already refreshed + const hasRefreshed = sessionStorage.getItem(REFRESH_KEY); + + if (!hasRefreshed) { + console.log("ChunkLoadError detected. Refreshing page..."); + + // Mark that we've refreshed + sessionStorage.setItem(REFRESH_KEY, "true"); + + // Force reload the page (bypassing cache) + window.location.reload(); + } else { + console.error("ChunkLoadError persists after refresh. There might be a deeper issue."); + + // Clear the flag after 30 seconds in case user navigates away and comes back + setTimeout(() => { + sessionStorage.removeItem(REFRESH_KEY); + }, 30000); + } + }; + + // Add event listeners + window.addEventListener("error", handleError); + window.addEventListener("unhandledrejection", handlePromiseRejection); + + // Cleanup event listeners + return () => { + window.removeEventListener("error", handleError); + window.removeEventListener("unhandledrejection", handlePromiseRejection); + }; + }, []); + + // This component doesn't render anything + return null; +} + diff --git a/docs/CHUNK_LOAD_ERROR_HANDLER.md b/docs/CHUNK_LOAD_ERROR_HANDLER.md new file mode 100644 index 00000000..041b045c --- /dev/null +++ b/docs/CHUNK_LOAD_ERROR_HANDLER.md @@ -0,0 +1,74 @@ +# Chunk Load Error Handler + +## Problem +ChunkLoadError terjadi ketika aplikasi Next.js mencoba memuat chunk JavaScript yang tidak lagi tersedia, biasanya terjadi karena: +- Deployment baru sementara user masih membuka halaman lama +- File chunk sudah berubah atau dihapus +- Network issues +- Cache issues + +Error ini menyebabkan tampilan web bermasalah dan user tidak bisa menggunakan fitur tertentu. + +## Solution +Implementasi automatic force refresh yang akan: +1. Mendeteksi ChunkLoadError secara otomatis +2. Melakukan force refresh **hanya sekali** untuk mencegah infinite reload loop +3. Menggunakan `sessionStorage` untuk tracking refresh state + +## Implementation + +### 1. Component: `chunk-load-error-handler.tsx` +Component client-side yang mendengarkan error events: +- `window.error` - untuk menangkap error reguler +- `window.unhandledrejection` - untuk menangkap promise rejections dari dynamic imports + +Component ini akan: +- Mendeteksi berbagai variasi ChunkLoadError +- Check apakah sudah pernah refresh (via sessionStorage) +- Jika belum, lakukan `window.location.reload()` untuk force refresh +- Jika sudah refresh tapi masih error, tidak akan refresh lagi (mencegah infinite loop) + +### 2. Integration di Root Layout +Component ditambahkan di root layout (`app/[locale]/layout.tsx`) agar berfungsi di seluruh aplikasi. + +## How It Works + +``` +User opens app → Deployment happens → User navigates → ChunkLoadError occurs + ↓ + Handler detects error + ↓ + Check sessionStorage + ↓ + No refresh yet? → Yes → Set flag & Reload + ↓ + Already refreshed? → Show error in console +``` + +## Benefits +✅ User experience lebih baik - no more broken page +✅ Automatic recovery dari ChunkLoadError +✅ Aman - hanya refresh sekali, tidak ada infinite loop +✅ Bekerja di background tanpa mengganggu user +✅ Works untuk semua tipe lazy-loaded components + +## Testing +Untuk test handler ini: +1. Build aplikasi: `npm run build` +2. Start production: `npm run start` +3. Buka aplikasi di browser +4. Build ulang aplikasi (tanpa menutup browser) +5. Navigate ke halaman yang menggunakan dynamic imports +6. Handler akan otomatis refresh jika terjadi ChunkLoadError + +## Monitoring +Check browser console untuk melihat log: +- `"ChunkLoadError detected. Refreshing page..."` - saat refresh pertama kali +- `"ChunkLoadError persists after refresh..."` - jika masih error setelah refresh + +## Notes +- SessionStorage akan di-clear otomatis setelah 30 detik jika error persists +- Handler tidak render apapun (return null) +- Zero impact pada performance +- Compatible dengan semua browser modern +