모바일 웹의 접근성과 사용성을 높이는 방법에는 여러 가지가 있지만, 그 중에서도 PWA 도입은 네이티브 앱에 가까운 사용자 경험을 제공할 수 있는 효과적인 방법입니다.
공연 공지 서비스 AMP는 서비스 목표에 맞게 공지 알림 기능을 제공하고, 더 나은 사용자 경험을 제공하고자 PWA 도입을 결정했습니다. 이번 글에서는 Vite 환경에서 vite-plugin-pwa 라이브러리를 활용해 PWA 설정을 진행하며 배웠던 것과, 어떻게 진행했는지를 기록하고자 합니다.

PWA는 웹과 네이티브 앱의 장점을 결합한 애플리케이션 형태입니다. 브라우저를 통해 접속하지만 홈 화면에 아이콘을 추가하여 앱처럼 간편하게 실행할 수 있습니다. 뿐만 아니라 오프라인 동작, 푸시 알림, 브라우저 UI가 최소화된 화면 등의 네이티브 앱과 유사한 사용자 경험을 제공할 수 있도록 해줍니다.
PWA에서 빼놓을 수 없는 개념이 Service Worker입니다. PWA가 네이티브 앱처럼 동작할 수 있는 이유가 바로 이 서비스 워커 때문입니다.
서비스 워커는 현재 보고 있는 웹페이지와는 별개로, 브라우저의 백그라운드에서 실행되는 자바스크립트 파일입니다. 즉, 브라우저의 네트워크 요청을 가로채고 제어할 수 있는 백그라운드 스크립트 역할을 합니다.
오프라인 캐싱 : 네트워크 연결이 끊기거나 불안정할 때, 서비스 워커가 미리 캐싱해둔 파일과 데이터를 보여줍니다.
백그라운드 동기화 및 푸시 알림 : 사용자가 웹 페이지를 닫아두어도 백그라운드에서 서버의 푸시 알림을 받을 수 있습니다. 이는 AMP 서비스에 PWA를 적용하는 최우선 목적이자 핵심 기능이기도 합니다.
원래라면 이 서비스 워커를 통해 어떤 자원을 캐싱할지, 언제 업데이트할지 등 복잡한 생명주기 로직을 개발자가 직접 다 작성해야 합니다.
하지만 Vite 환경에서는 vite-plugin-pwa 라이브러리를 사용하여 쉽게 PWA를 설정할 수 있습니다. vite-plugin-pwa는 빌드 시점에 이러한 서비스 워커를 자동으로 생성하고, manifest.json까지 주입해주기 때문에 개발자가 설정해야 할 요소들을 줄여줍니다.
vite-plugin-pwa 라이브러리를 사용할 때 설정해야 하는 요소들이 몇 가지 있습니다. 설정 과정에서 직접 사용했던 옵션을 중심으로 정리해보겠습니다.
registerType: 'autoUpdate'
새로운 버전이 배포되었을 때, 최신 서비스 워커를 자동으로 활성화하도록 설정합니다.
devOptions: {enabled: true}
원래 PWA 관련 기능은 별도의 빌드 환경에서만 동작하지만, 이 옵션을 켜두면 로컬 개발 환경에서도 PWA 기능을 바로 테스트할 수 있습니다.
includeAssets
서비스워커가 캐싱할 정적 에셋(로고 이미지, 파비콘 등)의 목록을 배열로 지정합니다. 해당 배열에 포함된 요소들은 미리 캐싱(precache)되기 때문에, 오프라인 상태에서도 아이콘이 정상적으로 보이게 해줍니다.
Manifest는 브라우저에게 이 웹앱이 사용자의 기기에 설치될 때 어떻게 보여야 하는지를 알려주는 설정 명세서입니다.
name, short_name
name은 설치 팝업이나 앱 실행 화면에 표시될 전체 이름입니다. 반면 short_name은 설치 후 홈 화면의 아이콘 아래에 표시될 짧은 이름입니다. 개발자나 기획 측 의도에 맞는 이름을 자유롭게 설정할 수 있습니다.
description
해당 웹앱에 대한 간단한 설명입니다. 검색 엔진 또는 앱 설치 프롬프트에서 활용될 수 있습니다.
theme_color
상태 표시줄이나 브라우저 테마 등 OS 수준에서 앱을 감싸는 UI의 배경색을 지정합니다. 이 또한 디자인 의도에 맞게 설정할 수 있습니다.
icons
앱이 기기에 설치되었을 때 표시될 아이콘들의 배열입니다. 최소한 192*192, 512*512 두 가지 사이즈의 이미지를 제공합니다. 추가로 iOS 기기 대응을 위해 180*180 사이즈의 전용 아이콘도 포함했습니다. 내부에 있는 purpose: 'any maskable' 속성은 안드로이드 환경에서 디바이스 마스킹 규칙에 맞춰 아이콘이 자연스럽게 잘릴 수 있도록 도와줍니다.
display: 'standalone'
앱이 실행될 때 브라우저의 URL 바 등 기본 브라우저 UI를 최소화하거나 숨깁니다. 유저는 이 앱이 웹 브라우저에서 돌아가는 것이 아니라, 네이티브 앱을 사용하는 것처럼 느끼게 합니다. (상태 표시줄까지 숨기는 fullscreen 등 그 외 옵션 또한 존재합니다.)
start_url: '/login'
유저가 PWA 아이콘을 클릭해서 앱을 실행했을 때, 최초로 진입할 경로를 지정할 수 있습니다. 현재 저희는 앱 실행 시 바로 로그인 화면을 마주하게끔 했습니다.
background_color
앱을 처음 켰을 때 화면에 콘텐츠가 렌더링 되기 전까지 잠깐 노출되는 배경색입니다.
위에서는 라이브러리가 서비스 워커를 알아서 만들어주는 방식이라면, 직접 작성한 서비스 워커 파일을 사용할 수도 있습니다.
AMP 서비스는 푸시 알림 기능을 직접 제어해야 했기 때문에, 자동 생성 방식보다는 커스텀 서비스 워커를 사용할 수 있는 injectManifest 전략을 선택했습니다.
strategies: 'injectManifest'
vite-plugin-pwa의 기본 전략인 generateSW, 즉 자동 생성 대신 개발자가 직접 작성한 서비스 워커 코드를 사용하겠다고 선언하는 옵션입니다. 빌드 시 Manifest만 우리가 만든 서비스 워커 파일에 주입해줍니다.
srcDir, filename
우리가 작성한 커스텀 서비스 워커 파일의 경로와 파일명을 선택하는 옵션입니다.
실제 코드로 보면, vite.config.ts 파일 내부 plugin 배열에 아래와 같이 설정했습니다.
VitePWA({
injectRegister: null,
registerType: 'autoUpdate',
devOptions: {
enabled: true,
type: 'module',
},
strategies: 'injectManifest',
srcDir: 'src',
filename: 'sw.ts',
includeAssets: [
'favicon.svg',
'amp-pwa-logo-192.png',
'amp-pwa-logo-512.png',
'amp-pwa-logo-180.png',
],
manifest: {
name: 'AMP',
short_name: 'AMP',
description: '작은 공지도 크게 울리게 공연 공지의 공식, AMP',
start_url: '/login',
display: 'standalone',
background_color: '#ffffff',
theme_color: '#ffffff',
icons: [
{
src: '/amp-pwa-logo-180.png',
sizes: '180x180',
type: 'image/png',
},
{
src: '/amp-pwa-logo-192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: '/amp-pwa-logo-512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: '/amp-pwa-logo-512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable',
},
],
},
}),

PWA 설정이 정상적으로 완료되면, 위와 같이 웹앱 형식으로 설치가 가능합니다.
이렇듯 Vite 환경에서 개발을 진행한다면, vite-plugin-pwa 라이브러리를 통해 복잡한 설정 없이도 Vite의 빌드 파이프라인 안에서 비교적 간단하게 PWA를 구축할 수 있었습니다.
각자 서비스의 상황에 맞게, 필요한 옵션과 적절한 Manifest를 설정하면 될 것 같습니다!