배포 후 발생하는 화면 깨짐 자동 복구
배포 후 이전 청크를 참조해 발생하던 화면 깨짐을 감지하고, 사용자 개입 없이 자동 복구하도록 개선
배경·문제
신규 버전을 배포하면 빌드 청크의 해시가 바뀝니다. 이전 index.html을 캐시하고 있던 브라우저는 더 이상 존재하지 않는 옛 해시의 청크를 요청하게 되고, 404와 함께 TypeError: Failed to fetch dynamically imported module 에러로 화면이 깨졌습니다.
사용자 입장에서는 왜 에러가 났는지 알 수 없고, 직접 새로고침을 눌러야만 해결되는 상황이었습니다.
해결 과정
1차 — 전역 이벤트 감지로 자동 새로고침. vite:preloadError, unhandledrejection 전역 리스너로 청크 로드 실패를 감지해 자동 reload를 시도했습니다.
2차 — 전역 리스너에 잡히지 않는 케이스 발견. 일부 React.lazy() 동적 import 실패는 전역 이벤트로 포착되지 않고 ErrorBoundary 경로로 처리되는 케이스가 있었습니다. 에러가 ErrorBoundary까지 올라가 사용자에게 일반 에러 페이지가 노출되고 있었습니다. 이를 해결하기 위해 ErrorBoundary에서 청크 로드 에러를 분기 감지하도록 보완했습니다.
getDerivedStateFromError에서 청크 에러 여부를 판별해, 일반 에러 페이지 대신 “최신 버전으로 패치되었습니다” 안내 오버레이를 표출- 5초 카운트다운 + progress bar 후 자동 새로고침, “지금 새로고침” 버튼도 함께 제공 — 에러 상황을 사용자에게 원인을 알 수 없는 에러 화면 대신 업데이트 안내를 제공
- 안내 오버레이는 외부 UI 라이브러리에 의존하지 않도록 구현해, UI 라이브러리 청크 로딩에 실패한 상황에서도 표시될 수 있도록 구성

3차 — 무한 새로고침 방지 guard. 새로고침으로도 해결되지 않는 상황(영구적인 청크 부재, 네트워크 장애)에서 무한 reload 루프에 빠지지 않도록 guard를 설계했습니다.
- 10초 가드가 걸린 `reloadOnce()`를 ErrorBoundary와 전역 리스너가 공유 — 두 경로에서 중복 호출돼도 reload는 한 번만 실행
- ErrorBoundary의 5초 안내 오버레이가 우선 동작하도록 전역 리스너의 reload를 6초 지연
- 10초 내에 다시 실패하면 영구 장애로 판단하고 안내를 닫고 일반 에러 페이지로 폴백
동작 흐름
- 1
청크 fetch 실패
React.lazy() 동적 import 실패 → ErrorBoundary에서 감지
- 2
청크 에러 판별
일반 에러와 분기
- 3
패치 안내 오버레이
5초 카운트다운 + 지금 새로고침 버튼
- 4
reloadOnce()
새 entry · 청크로 진입 (10초 가드, 1회만 실행)
- 5
재실패 시 폴백
10초 내 재실패 = 영구 장애 → 일반 에러 페이지
검증
- dev 서버에서는 stale-chunk 상황 재현이 어려워, 임시 미리보기 버튼을 추가해 오버레이 디자인·카운트다운 동작을 검증한 뒤 제거
- 프로덕션 배포 후 실제 stale-chunk 상황에서 안내 → 자동 reload 1회 동작 확인
결과
- 배포 직후 발생하던 화면 깨짐을 사용자 개입 없이 자동 복구
- 원인을 알 수 없는 일반 에러 화면 대신 업데이트 안내를 제공해 사용자가 상황을 이해할 수 있도록 개선