Vue+Vite 환경에서 배포 후 흰화면 발생할 때

Heina·2025년 5월 9일
0

🔴 발생한 문제

개발서버에 개발한것을 반영하였을 때, 모바일웹앱을 실행하면 이전 화면이 나타나지 않고 흰 화면이 나타나는 매혹적이고 치명적인 오류가 발생했다.

그래서 테스트를 하거나 앱을 시연할 때 앱 캐시를 한번 날리고 진행했다.

그렇게 연명하며 살던 도중 우리는 오류를 발견하였는데

🔍발견한 오류

Uncaught (in promise) TypeError: Failed to fetch dynamically imported module:
https://.../assets/atdrnModify-37776692.js

앱이 기능을 실행할 때 필요한 파일 atdrnModify-37776692.js 을 불러오려고 했는데, 그 파일이 서버에 없어서 실패한 상황이다.

🧨 문제 발생의 이유

앱은 기능별로 파일을 쪼개서 불러온다. (동적 import)

Vue + Vite는 성능을 위해 화면 전환 시 필요한 기능만 동적으로 불러오는 방식(lazy loading) 을 사용한다.

새로 배포하면 파일명이 바뀐다.

새로운 버전이 배포되면, 기존에 있던 atdrnModify-37776692.js 같은 파일은 삭제되고,
대신 atdrnModify-11223344.js 처럼 새 이름의 파일이 생성된다.

모바일 사용자는 오래된 페이지를 볼 수 없다.

예를 들어, A 사용자가 오전에 웹앱을 켜둔 채 3시간 뒤에 다시 화면을 눌렀을 때:
→ 이미 서버에는 옛날 파일이 사라졌고, 앱은 여전히 옛날 파일을 불러오려 해서 실패한다.

🧠 해결을 위한 고민

💡문제 해결을 위한 방법들

1. 모든 파일 이름을 고정시키기

chunk 파일명을 고정시켜 삭제 문제 방지
단, 캐시 문제가 생기기 쉬워 권장되지 않음

2. PWA 캐시 강제 삭제

서비스워커에서 캐시를 지우고 새 버전 강제 로드
이건 설정이 복잡하고 테스트가 어려워 (내가) 함부로 건들 수 있는 영역이 아니라 패스

3. 안내 후 새로고침

에러가 나면 “새로고침 하시겠습니까?” 라는 안내창 표시
해당 방법은 기획과 이야기가 되지 않았고, 만약 사용자가 거절하면 문제가 지속되는 문제가 있음...

4. 앱 새로고침

문제가 생기면 자동 새로고침해서 최신 버전을 로드
단, 사용자 경험이 조금 끊긴다

그래서 난 가장 해결이 간단하고 확실한 해결책을 사용하기로 했다.
사용자도 웹앱을 다시 껏다 켠 것 같은 느낌만 받을 뿐, 앱이 멈추거나 흰 화면이 노출되지는 않을테니까 (아마도)

✅ 해결

main.js에 설정해 두었다

// Vite가 동적 파일을 못 불러오면
window.addEventListener('vite:preloadError', (event) => {
  event.preventDefault(); // 기본 에러 막고
  window.location.reload(); // 자동 새로고침
});

// Vue Router가 lazy import 실패 시
router.onError((error) => {
  if (/Failed to fetch dynamically imported module/.test(error.message)) {
    window.location.reload();
  }
});

배포 후 확인해 보았을 때 아직까지 흰화면 발생하는 현상은 발견하지 못했다.
만약 추후에 발견될 경우 추가적으로 조치 예정

번외

Hash 가 도대체 뭐야

관련 문제들을 검색했을 때 Vue-Router에서 사용하는 URL 모드를 수정하라는 방법과, vite.config.js에 캐시제어를 하라는 방법들이 많이 나타났다.

🔹 1. createWebHistory() or createWebHashHistory() 란?

import { createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(), // 히스토리 모드
  routes,
})

📌 createWebHistory()

  • 브라우저의 History API를 사용해서 URL에 # 없이 깔끔한 경로(/home) 를 사용한다. 예: https://example.com/home

📌 createWebHashHistory()

즉, 라우팅 방식의 차이를 말한다.

2. [hash] in vite.config.js란?

rollupOptions: {
  output: {
    entryFileNames: '[name].[hash].js',
    chunkFileNames: '[name].[hash].js',
    assetFileNames: 'assets/[name].[hash].[ext]',
  },
},

빌드된 파일명에 [hash]를 붙이면, 파일 내용이 바뀌면 이름도 바뀜
예: main.js → main.abc123.js

이는 브라우저 캐시를 무력화 시키기 위한 파일 캐싱 제어 방법이다.

0개의 댓글