-
웹앱을 배포했는데 열린 탭만 옛날 버전인 이유Programming 2026. 10. 5. 00:20728x90반응형

새 worker의 활성화와 열린 페이지의 코드 갱신은 서로 다른 단계입니다. 새 창에서는 바뀐 화면이 뜨는데 오전부터 열어 둔 탭은 그대로라면, 배포 파일부터 다시 올리기 전에 Service Worker의 상태를 보세요. Service Worker의 설치·대기·활성화와 현재 페이지의 controller를 구분하고, 사용자 작업을 보존한 뒤 버전을 전환하세요.
Service Worker를 쓰는 웹앱에서는 새 파일의 배포, 새 worker의 설치, 열린 페이지의 전환이 서로 다른 시점에 일어납니다. 새 worker가
waiting에 있다는 것은 설치 후 기존 페이지들이 끝나기를 기다리는 상태일 수 있습니다.아래 메모 앱의 v1·v2는 갱신 흐름을 설명하는 가상 버전입니다. 2026년 9월 28일 확인한 공식 개발 문서에 근거하며, 실제 사용자의 탭이나 저장 자료를 변경하지 않았습니다.
두 탭이 열린 메모 앱에서 생기는 일
탭 A와 B가 v1 페이지를 실행 중이고, 둘 다 v1 worker의 제어를 받는다고 하겠습니다. 그동안 서버에 v2를 배포하고 브라우저가 변경된 worker를 발견합니다. v2의 설치가 성공해도 v1이 제어하는 페이지가 남아 있으면 기본 흐름에서는 대기합니다.
이때 A에서 새로고침 한 번을 눌렀다고 전환이 끝나지 않을 수 있습니다. 탐색 도중 기존 페이지와 새 페이지의 생애가 겹칠 수 있고, B도 여전히 v1을 사용하고 있기 때문입니다. web.dev의 생애주기 문서는 이 겹침 때문에 단일 탭에서도 새로고침만으로 대기가 끝나지 않을 수 있다고 설명합니다. Service Worker 갱신 생애주기
B를 찾지 못한 채 A에서 캐시 삭제를 반복하면 원인을 관찰하기 어려워집니다. 우선 같은 앱의 다른 탭과 설치형 앱 창이 있는지, 입력 중인 내용이 있는지 확인하세요. 모든 창을 닫으면 전환되는지를 보는 검사는 쓸 수 있지만, 미저장 메모가 있을 때 곧바로 실행할 조치는 아닙니다.
등록 객체와 현재 페이지를 함께 봅니다
개발 중에는 다음처럼 현재 URL에 해당하는 등록 상태와 페이지 제어자를 읽을 수 있습니다. 등록이나 캐시를 바꾸지 않는 관찰용 코드입니다. Service Worker를 지원하는 보안 컨텍스트에서 실행하는 예시입니다.
const sw = navigator.serviceWorker; const reg = await sw.getRegistration(); console.log({ installing: reg?.installing?.state, waiting: reg?.waiting?.state, active: reg?.active?.state, controller: sw.controller?.scriptURL, });installing은 설치 중인 worker,waiting은 설치 후 대기하는 worker,active는 활성 worker입니다.controller는 이 페이지를 제어하는 worker를 가리킵니다. 등록에 active가 있어도 처음 방문한 페이지는 아직 제어되지 않을 수 있습니다. 등록 상태의 속성, 현재 페이지의 controller여기서
scriptURL만으로 v1과 v2를 구분할 수는 없습니다. 두 버전이 같은/sw.js주소로 배포될 수 있기 때문입니다. 앱 화면의 빌드 식별자와 worker가 응답하는 버전 정보 등 자신이 마련한 표시를 함께 확인해야 합니다. 위 코드는 상태를 좁혀 줄 뿐 버전 검사를 완성하지는 않습니다.메모 앱에서 v2가 waiting이고 현재 화면은 v1이라면 설치 실패부터 의심할 이유는 줄어듭니다. 반면 installing 단계에서 끝나고 waiting도 없다면 설치 이벤트의 오류나 자원 준비 실패를 조사해야 합니다. 앱에 등록 자체가 없다면 HTTP 캐시나 배포 경로 등 다른 원인으로 돌아갑니다.
skipWaiting을 넣으면 페이지와 worker 버전이 섞일 수 있습니다
skipWaiting()은 새 worker가 대기를 건너뛰고 활성화되도록 요청합니다. 설치 과정까지 생략하지는 않습니다. skipWaiting문제는 이미 열린 페이지입니다. v1 페이지의 JavaScript는 메모리에서 계속 실행 중인데 이후 요청을 새 worker가 처리하면 서로 다른 버전이 만납니다. worker가 활성화됐다는 이유로 페이지 코드까지 v2가 된다고 생각하면 이 조합을 놓치게 됩니다.
가상의 v1 메모 편집기가 사용자가 버튼을 누를 때
/editor-v1.js를 나중에 읽는다고 하겠습니다. v2 배포 과정에서 이 파일을 지웠다면 오래 열린 v1 페이지는 그 버튼을 누르는 순간 실패할 수 있습니다. 여기서 검수할 것은 새 첫 화면뿐 아니라 구버전 페이지의 늦은 요청입니다. 파일 보존 기간과 캐시 정리 시점도 이 요청을 고려해 정해야 합니다.API 응답이나 로컬 저장 형식을 바꾸는 앱도 같은 방식으로 살펴볼 수 있습니다. v1이 해석하지 못하는 자료를 v2가 돌려주는 조합이 가능한지, 새 형식으로 저장한 메모를 이전 탭이 다시 읽는지 확인합니다. 이 위험은 앱의 계약에 따라 달라지므로 무조건 즉시 전환하거나 무조건 기다리라는 결론으로 통일할 수 없습니다.
clients.claim은 새 화면을 띄우는 명령이 아닙니다
활성 worker의
clients.claim()은 자신의 범위에 있는 페이지를 제어하도록 합니다. 해당 페이지는controllerchange이벤트로 제어자 변경을 관찰할 수 있습니다. clients.claim이 호출과
skipWaiting()은 서로 다른 단계에 작용합니다. 대기를 끝내는 동작과 페이지를 제어하는 동작을 구분해야 첫 방문과 업데이트를 따로 설계할 수 있습니다. 두 호출 어느 쪽도 사용자의 입력을 저장하거나 페이지의 JavaScript를 새 코드로 다시 실행해 주지는 않습니다.예를 들어 새 페이지를 다시 읽도록 하려면 앱에서 재로딩 시점을 정해야 합니다.
controllerchange마다 무조건 재로딩하면 사용자가 쓰던 내용을 잃거나 구현에 따라 반복 탐색을 만들 수 있습니다. 이 전환을 한 번 처리했는지, 미저장 입력이 있는지, 저장 요청이 끝났는지를 앱 상태와 함께 관리합니다.메모 앱에는 업데이트 버튼 앞뒤의 동작이 필요합니다
v2가 준비되면 ‘새 버전으로 열기’ 안내를 보여 주되 사용자가 A에서 작성하던 내용을 보존하는 흐름을 먼저 정할 수 있습니다. 다음은 구현 코드가 아닌 검수 시나리오입니다.
- A에서 메모를 수정하고 B도 같은 앱으로 열어 둡니다.
- v2를 배포해 A의 등록에서 waiting 상태가 관찰되는지 봅니다.
- A의 저장이 끝난 뒤 전환을 선택합니다. B가 아직 v1인 경우의 동작도 정해 둡니다.
- 제어자 변경과 필요한 재로딩을 처리합니다.
- 새 화면의 버전과 저장된 메모를 확인하고, 편집·저장 같은 후속 요청을 다시 수행합니다.
새 화면이 떴는데 메모가 사라졌다면 전환 과정에서 자료 보존이 실패한 것입니다. 메모는 남았지만 화면 버전이 그대로라면 전환 단계가 남아 있습니다. 같은 ‘업데이트 성공’ 한 칸으로 기록하지 않아야 어느 부분을 고칠지 알 수 있습니다.
캐시는 앱이 소유한 이름과 버전에 한해 정리합니다. 강제 활성화와 함께 v1 캐시를 지운다면 살아 있는 v1 페이지가 여전히 그 자원을 필요로 하는지 먼저 검토하세요. 다른 앱의 캐시까지 전부 지우는 조치는 업데이트 설계를 대신할 수 없습니다.
개발자 도구의 강제 업데이트 옵션은 이 흐름을 빠르게 건너뛸 수 있습니다. 마지막 검수에서는 그 옵션을 끄고 새 방문, 두 탭 유지, 미저장 입력, 전환 후 요청을 확인하세요. 열린 탭의 구버전 문제는 실제 사용자가 거치는 갱신 경로에서 끝내야 합니다.
728x90반응형'Programming' 카테고리의 다른 글
오프라인 파일 하나가 404인데 왜 설치 전체가 실패할까 (0) 2026.10.04 다른 탭에 변경을 알렸는데 새로 연 탭은 모르는 이유 (0) 2026.10.04 탭 두 개가 같은 작업을 동시에 할 때: Web Locks의 범위 (0) 2026.10.04 복사 버튼은 눌렀는데 클립보드가 안 바뀌는 이유 (0) 2026.10.04 자동재생을 켰는데 비디오가 멈춰 있는 이유 (0) 2026.10.04