목록 보기
S3 + CloudFront 기반 SPA 배포에서 캐시와 fallback 전략 설계하기
데브옵스

S3 + CloudFront 기반 SPA 배포에서 캐시와 fallback 전략 설계하기

쏘카
쏘카
2026년 6월 23일

두줄요약

S3·CloudFront 기반 SPA에서 HTML, hashed asset, route fallback의 캐시 책임을 분리했습니다.\n누락 asset은 404로 유지하고 chunk 오류에는 1회 새로고침 방어를 적용했습니다.

문제 상황

  • 새 프론트 배포 뒤 이미 열려 있던 웹뷰의 lazy route 이동에서 ChunkLoadError와 dynamic import 실패 발생
  • 누락된 JavaScript asset이 전역 SPA fallback에 의해 index.html 200 응답으로 치환되며 MIME type mismatch로 표면화

원인 분석

  • 구버전 SPA runtime이 메모리에 남아 이전 hashed chunk를 요청하고, 최신 S3 release prefix에 해당 파일 부재
  • CloudFront invalidation이 edge cache만 비우며 브라우저·웹뷰 캐시와 실행 중 runtime은 교체하지 못하는 구조
  • Custom Error Response의 전역 403·404 fallback이 route와 asset 요청을 구분하지 못하는 문제

해결 방법

  • index.html은 no-cache 재검증, hashed assets는 immutable 장기 캐시로 S3 metadata와 CloudFront behavior 분리
  • Custom Error Response 제거 후 CloudFront Function으로 확장자 없는 SPA route만 /index.html로 rewrite
  • invalidation을 /index.html과 /로 축소하고, chunk load error에는 reload-once 및 수동 새로고침 fallback 적용

성능/운영 포인트

  • 공통 배포 action의 기본 recursive upload를 비활성화하고 assets와 HTML을 서로 다른 Cache-Control로 직접 업로드
  • /assets/* 누락 요청의 403·404 유지와 SPA route의 HTML 응답을 배포 후 검증 계약으로 정의
  • 프레임워크별 런타임 감지 방식과 무관하게 chunk 실패 감지, 1회 재시도, 재실패 시 안내 UI 원칙으로 표준화

다음 읽기

#Vite 주제를 다룬 다른 회사 글

집 나간 네트워크는 돌아왔는데 React.lazy는 왜 안 돌아올까

네트워크 복구 후에도 React.lazy 재시도가 막히는 이유를 모듈 맵 캐시로 설명했습니다. 정적 import 전환과 사전 로딩으로 오류를 해결했습니다.

우아한 형제들
우아한 형제들
프론트엔드

댓글 0개

댓글을 작성하려면 로그인이 필요합니다.

댓글을 불러오는 중...