React.lazy와 청크 오류: 배포 후 갇힌 사용자 복구 방법
발행: (2026년 5월 25일 AM 01:11 GMT+9)
3 분 소요
원문: Dev.to
출처: Dev.to
클래식한 React 프로덕션 버그: 새로운 번들을 배포했는데 사용자는 탭에 오래된 HTML을 캐시하고 있고, 라우트로 이동하면 → React.lazy()가 더 이상 CDN에 존재하지 않는 청크를 가져오려고 시도 → 화면이 빈칸이 됩니다.
https://cdn.example.com/assets/Page-abc123.js
사용자는 강제 새로고침 외에 탈출구가 없으며, 대부분은 그 방법을 모릅니다.
청크 로드 오류를 잡아내고 캐시 무효화 파라미터와 함께 페이지를 강제 새로고침하는 전역 오류 리스너:
const CHUNK_ERROR_PATTERNS = [
/Loading chunk \d+ failed/i,
/Failed to fetch dynamically imported module/i,
/Loading CSS chunk .* failed/i,
/Importing a module script failed/i,
];
window.addEventListener('error', (e) => {
const msg = e?.message || '';
if (CHUNK_ERROR_PATTERNS.some(rx => rx.test(msg))) {
const url = new URL(window.location.href);
url.searchParams.set('_r', String(Date.now()));
window.location.replace(url.toString());
}
});
각 부분이 중요한 이유:
- 여러 패턴: 브라우저마다 다른 메시지를 던집니다. Safari는
"Importing a module script failed"를, Chrome은"Failed to fetch dynamically imported module"을, 오래된 Webpack 빌드는"Loading chunk N failed"를 사용합니다. - 대소문자 구분 없음: 일부 브라우저는 대문자를, 일부는 소문자를 사용합니다.
- 캐시 무효화 파라미터:
?_r=를 추가하면 새로운index.html을 강제로 받아오게 되며, 여기에는 새로운 청크 해시가 포함됩니다. replace()가assign()이 아닌 이유: 히스토리 항목을 추가하지 않으므로 뒤로 가기 버튼이 정상 작동합니다.
주의사항
lazyimport가 프로미스 내부에서 오류를 발생시키면unhandledrejection도 잡히므로, 누락되는 경우 두 번째 리스너를 추가하세요.- 네트워크 장애 시 무한 루프에 빠지지 않도록 한 번만 새로고침하도록 플래그를 두세요.
- 테스트 방법: 새 빌드를 배포하고, 오래된 탭을 열어 라우트 이동을 시도하면 자동으로 복구되는지 확인합니다.
15줄 정도의 코드지만, 배포 후 앱을 포기하는 사용자를 실제로 상당히 줄여줍니다.