PWA는 웹의 장점(URL, 검색)과 앱의 장점(오프라인, 설치)을 동시에 취하는 전략입니다.

개념 정의

PWA(Progressive Web App) 는 웹 기술로 만든 앱이 네이티브 앱처럼 설치, 오프라인 사용, 푸시 알림이 가능하도록 하는 기술 집합입니다.

Web App Manifest

JSON
// 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" }
  ]
}
SVELTE
<!-- 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를 기본 지원합니다.

JAVASCRIPT
// 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'))
  );
});

오프라인 페이지

SVELTE
<!-- src/routes/offline/+page.svelte -->
<h1>오프라인 상태입니다</h1>
<p>인터넷 연결을 확인해주세요.</p>

설치 프롬프트

SVELTE
<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가 완성됩니다.

댓글 로딩 중...