PWA — SvelteKit으로 프로그레시브 웹 앱 만들기
PWA는 웹의 장점(URL, 검색)과 앱의 장점(오프라인, 설치)을 동시에 취하는 전략입니다.
개념 정의
PWA(Progressive Web App) 는 웹 기술로 만든 앱이 네이티브 앱처럼 설치, 오프라인 사용, 푸시 알림이 가능하도록 하는 기술 집합입니다.
Web App Manifest
// static/manifest.json
{
"name": "내 SvelteKit 앱",
"short_name": "SvelteApp",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#ff3e00",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
<!-- src/routes/+layout.svelte -->
<svelte:head>
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#ff3e00" />
</svelte:head>
Service Worker
SvelteKit은 src/service-worker.js에서 Service Worker를 기본 지원합니다.
// src/service-worker.js
/// <reference types="@sveltejs/kit" />
import { build, files, version } from '$service-worker';
const CACHE = `cache-${version}`;
const ASSETS = [...build, ...files];
// 설치 — 정적 자산 캐싱
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE)
.then(cache => cache.addAll(ASSETS))
.then(() => self.skipWaiting())
);
});
// 활성화 — 이전 캐시 삭제
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys()
.then(keys => Promise.all(
keys.filter(key => key !== CACHE).map(key => caches.delete(key))
))
.then(() => self.clients.claim())
);
});
// 요청 가로채기 — 캐시 우선 전략
self.addEventListener('fetch', (event) => {
if (event.request.method !== 'GET') return;
event.respondWith(
caches.match(event.request)
.then(cached => cached || fetch(event.request))
.catch(() => caches.match('/offline.html'))
);
});
오프라인 페이지
<!-- src/routes/offline/+page.svelte -->
<h1>오프라인 상태입니다</h1>
<p>인터넷 연결을 확인해주세요.</p>
설치 프롬프트
<script>
import { onMount } from 'svelte';
let deferredPrompt = $state(null);
let showInstallBanner = $state(false);
onMount(() => {
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
showInstallBanner = true;
});
});
async function installApp() {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log(outcome === 'accepted' ? '설치됨' : '거절됨');
deferredPrompt = null;
showInstallBanner = false;
}
</script>
{#if showInstallBanner}
<div class="install-banner">
<p>앱으로 설치하시겠습니까?</p>
<button onclick={installApp}>설치</button>
<button onclick={() => showInstallBanner = false}>닫기</button>
</div>
{/if}
면접 포인트
- "PWA의 핵심 3요소는?": HTTPS, Web App Manifest(메타데이터), Service Worker(오프라인/캐싱)입니다.
- "Service Worker 캐싱 전략의 차이는?": Cache First(오프라인 우선), Network First(최신 데이터 우선), Stale While Revalidate(캐시 반환 후 백그라운드 업데이트) 등이 있습니다.
정리
SvelteKit은 Service Worker를 기본 지원하므로 PWA 구현이 자연스럽습니다. manifest.json + Service Worker + 오프라인 페이지 세 가지만 설정하면 기본적인 PWA가 완성됩니다.
댓글 로딩 중...