본문으로 건너뛰기

안동민 개발노트

본문 시작

Progressive Web Apps (PWA) 소개

HTTPS 위에 매니페스트와 서비스 워커를 구성해 설치·오프라인 캐시·푸시 알림을 지원하는 PWA 원리를 익힙니다.

우리는 지금까지 프론트엔드와 백엔드 핵심 기술을 익히고, 데이터베이스, 보안, 성능, 개발 도구까지 폭넓게 다뤘습니다.

이제 기본 웹 애플리케이션을 기획하고 배포할 수 있는 기반이 갖춰졌습니다.

다음 질문은 앞으로 무엇을 더 준비해야 하는가입니다.

웹 기술은 빠르게 바뀌고, 오늘의 선택이 내일의 기본이 되기도 합니다.

15장에서는 이런 변화 속에서 실제로 영향력이 큰 흐름을 살펴봅니다.

첫 주제는 PWA(Progressive Web App)입니다.

PWA는 웹 앱을 네이티브 앱에 가까운 경험으로 끌어올리는 접근입니다.

설치, 오프라인 지원, 푸시 알림처럼 웹의 한계를 확장하는 기술을 중심으로 구성됩니다.

사용자 필요 기반 PWA 기능 결정

FLOWCHART · B99 WEB FUNDAMENTALS

사용자 필요 기반 PWA 기능 결정

PWA는 secure context 위에서 manifest·service worker·cache and update policy를 조합해 설치·오프라인·push 등 선택적 기능을 제공한다. service worker는 register·install·waiting·activate·fetch와 update 수명을 가지며 기존 page가 새 worker 적용 시점을 좌우한다.

사용자 필요 기반 PWA 기능 결정 검증된 사용자 작업 문제와 secure context 및 플랫폼 지원을 먼저 확인하고 install offline push background 가운데 필요한 최소 기능만 권한 저장소 운영 비용과 fallback을 포함해 채택하는 지도 검증된 사용자 문제브라우저 기능이 해결하는가? 공통 선행 조건secure context · 플랫폼 지원 · 일반 웹 fallback권한·저장소·배터리·운영 비용 확인 설치반복 진입 단축manifest · icons · UX 오프라인핵심 여정 지속cache expiry · storage push시간 민감 알림명시적 opt-in · 해지 background지연 전송·동기화quota · battery · support 각 기능을 독립 평가해 최소 기능만 채택필요·지원·권한·운영 조건 실패 시 일반 웹 경로

먼저 확인

실제 사용자 문제, secure context, 플랫폼 지원, 일반 웹 fallback, 운영 비용

설치

반복 진입을 줄여야 하고 manifest·icons·설치 UX를 유지할 수 있을 때

오프라인

네트워크 없이 핵심 여정을 지속해야 하며 cache expiry·storage를 운영할 때

push

시간 민감 알림에 사용자가 명시적으로 opt-in하고 쉽게 해지할 수 있을 때

background

지연 전송·동기화가 필요하고 quota·battery·플랫폼 제약을 감당할 때

채택 게이트

네 기능을 각각 평가하고 사용자 필요와 선행 조건을 통과한 최소 capability만 채택한다. 나머지는 일반 웹 경로를 유지한다.

PWA는 기능 묶음이 아니다. 사용자 문제를 해결하는 최소 capability만 채택하고 모든 권한 거부·미지원 상태에 웹 fallback을 둔다.


PWA (Progressive Web App)란?

PWA (Progressive Web App)는 웹 기술(HTML, CSS, JavaScript)을 사용하여 개발되었지만, 네이티브 애플리케이션(iOS, Android 앱)과 유사한 사용자 경험을 제공하는 웹 애플리케이션입니다.

PWA는 웹의 장점(설치 필요 없음, URL 기반 접근 용이성, 빠른 개발 및 배포)과 네이티브 앱의 장점(오프라인 지원, 푸시 알림, 홈 화면 아이콘, 시스템 자원 접근)을 결합하여 사용자에게 더욱 풍부하고 편리한 경험을 제공하는 것을 목표로 합니다.

왜 PWA가 중요한가?
  • 설치 장벽 낮춤: 사용자는 앱 스토어 방문, 다운로드, 설치 과정 없이 웹사이트 방문만으로 PWA를 사용하고, 필요하면 홈 화면에 추가할 수 있습니다. 이는 사용자 유입 장벽을 크게 낮춥니다.
  • 접근성 향상: 낮은 네트워크 환경에서도 동작하며, 푸시 알림을 통해 사용자 재참여를 유도할 수 있습니다.
  • 개발 및 유지보수 효율: 하나의 코드베이스로 모든 플랫폼(웹, 모바일)에 대응 가능하여 개발 비용과 시간을 절감합니다. 웹 표준 기술을 사용하므로 별도의 스킬셋을 익힐 필요가 적습니다.
  • SEO 이점: 웹사이트이므로 검색 엔진에 노출되며, 빠른 로딩 속도와 좋은 사용자 경험은 SEO 랭킹에도 긍정적인 영향을 미칩니다.

PWA의 핵심 구성 요소

Progressive Web Apps (PWA) 소개에서는 실행 환경, 배포 구조, 사용자 경험 기준을 정리합니다.

PWA는 다음 세 가지 핵심 기술과 여러 권장 사항을 바탕으로 구현됩니다.

서비스 워커 (Service Worker)

  • PWA의 핵심 실행 계층: 서비스 워커는 웹 페이지와 독립적으로 백그라운드에서 실행되는 JavaScript 파일입니다. 네트워크 요청을 가로채고, 캐싱 전략을 프로그래밍 방식으로 제어하며, 푸시 알림을 수신하는 등의 역할을 수행합니다.

  • 주요 기능
    • 오프라인 지원 (Offline-first): 네트워크 연결이 없거나 불안정한 환경에서도 캐시된 콘텐츠를 제공하여 웹 앱이 동작하도록 합니다.
    • 빠른 로딩: 네트워크 요청을 가로채 캐시된 리소스를 즉시 반환함으로써 페이지 로딩 속도를 비약적으로 향상시킵니다.
    • 푸시 알림 (Push Notifications): 사용자가 웹 앱을 닫은 상태에서도 서버로부터 푸시 메시지를 받아 알림을 표시할 수 있게 합니다.
    • 백그라운드 동기화: 네트워크가 다시 연결될 때까지 데이터를 저장하고 있다가 백그라운드에서 서버와 동기화할 수 있습니다.
  • 동작 방식 (간략)

    웹 페이지에서 서비스 워커를 등록(Register)합니다.

    브라우저는 서비스 워커 파일을 다운로드하고 설치(Install)합니다.

    이 단계에서 필요한 에셋들을 캐시에 저장할 수 있습니다.

    서비스 워커가 활성화(Activate)되면 이후 모든 네트워크 요청을 가로채서(Fetch) 개발자가 정의한 캐싱 전략에 따라 응답을 제공합니다.

웹 앱 매니페스트 (Web App Manifest)

  • PWA의 신분증: 웹 앱 매니페스트는 JSON 형식의 파일로, PWA의 메타데이터(이름, 아이콘, 시작 URL, 표시 방식 등)를 정의합니다.
  • 주요 기능
    • 홈 화면 아이콘: 사용자가 PWA를 홈 화면에 추가했을 때 표시될 아이콘을 정의합니다.
    • 시작 화면 (Splash Screen): 앱을 실행할 때 표시되는 스플래시 화면을 정의합니다.
    • 표시 모드 (Display Mode): PWA가 브라우저 UI 없이 독립적인 앱처럼 실행될지(standalone), 최소한의 UI를 가질지(minimal-ui), 아니면 일반 웹 페이지처럼 보일지(browser) 등을 설정합니다.
    • 시작 URL: PWA를 실행했을 때 로드될 초기 URL을 지정합니다.
  • index.html에 연결: <link rel="manifest" href="/manifest.json"> 형태로 HTML 파일에 연결합니다.

HTTPS

  • PWA의 필수 조건: PWA는 서비스 워커의 보안 및 무결성 문제 때문에 반드시 HTTPS 환경에서 호스팅되어야 합니다. 로컬 개발 환경(localhost)에서는 예외적으로 HTTP가 허용됩니다.
  • 보안과 신뢰: HTTPS는 웹 페이지와 서버 간의 통신을 암호화하여 데이터 유출 및 변조를 방지하고, 사용자에게 신뢰성을 제공합니다.

PWA의 주요 특징 및 장점

PWA는 네이티브 앱의 장점을 웹으로 가져오면서도 웹 본연의 장점을 유지합니다.

특징PWA네이티브 앱 (iOS/Android)
설치앱 스토어 불필요, 홈 화면 추가앱 스토어/플레이 스토어를 통해 설치
접근성URL로 직접 접근 가능, 즉시 사용검색/설치 과정 필요
오프라인서비스 워커로 지원 가능기본적으로 지원
푸시 알림지원 가능지원 가능
업데이트웹페이지처럼 자동으로 업데이트 (재방문 시)앱 스토어/플레이 스토어를 통해 수동 업데이트 또는 자동
개발 비용단일 코드베이스, 웹 기술 사용으로 효율적플랫폼별(iOS/Android) 개별 개발 필요 (높은 비용)
배포웹서버에 배포, 즉시 반영앱 스토어 심사 필요 (시간 소요)
시스템 접근제한적 (카메라, 마이크, GPS 등 일부 가능)전반적인 시스템 자원(주소록, 캘린더 등) 접근 용이
용량초기 다운로드 용량 적음일반적으로 용량이 큼
SEO검색 엔진 노출 용이검색 엔진 노출 어려움 (앱 스토어 내 검색 위주)

PWA 구현의 간단한 흐름 (예시)

매니페스트 파일 (manifest.json) 생성
manifest.json
{
  "name": "My Awesome PWA",
  "short_name": "My PWA",
  "start_url": ".",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#000000",
  "icons": [
    {
      "src": "/logo.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/logo.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}
HTML에 매니페스트 링크 추가
<head>
    <link rel="manifest" href="/manifest.json">
    <meta name="theme-color" content="#000000">
    <link rel="apple-touch-icon" href="/logo.png">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
</head>
서비스 워커 파일 (sw.js) 생성 및 캐싱 전략 정의
sw.js
// sw.js (간단한 예시 - 캐시 우선 전략)
const CACHE_NAME = 'my-pwa-cache-v1';
const urlsToCache = [
  '/',
  '/index.html',
  '/styles.css',
  '/script.js',
  '/logo.png',
  // ... 기타 중요한 리소스
];

// 서비스 워커 설치 시점에 캐시할 리소스 정의
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

// 네트워크 요청 가로채기 (캐시 우선 전략)
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // 캐시에 응답이 있으면 캐시된 응답 반환
        if (response) {
          return response;
        }
        // 캐시에 없으면 네트워크에서 가져옴
        return fetch(event.request).then(
          response => {
            // 가져온 응답을 캐시에 저장 (나중에 사용할 수 있도록)
            if (!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }
            const responseToCache = response.clone();
            caches.open(CACHE_NAME)
              .then(cache => {
                cache.put(event.request, responseToCache);
              });
            return response;
          }
        );
      })
  );
});

// 오래된 캐시 삭제
self.addEventListener('activate', event => {
  const cacheWhitelist = [CACHE_NAME];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});
메인 JavaScript 파일에서 서비스 워커 등록
script.js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(registration => {
        console.log('Service Worker registered: ', registration);
      })
      .catch(error => {
        console.error('Service Worker registration failed: ', error);
      });
  });
}

HTTPS 환경에서 서비스 배포.

(또는 개발 시 localhost 사용)

참고: Vite, Next.js 같은 최신 프론트엔드 도구는 플러그인 기반으로 PWA를 구성합니다.

예를 들어 Vite는 vite-plugin-pwa를 추가해 서비스 워커/매니페스트를 명시적으로 관리하는 방식이 일반적입니다.

PWA는 구현 후에도 캐시 갱신, 설치 가능성, 오프라인 동작을 실제 기기에서 반복 점검해야 합니다.

서비스 워커 설치·갱신 생명주기

STATE · B99 WEB FUNDAMENTALS

서비스 워커 설치·갱신 생명주기

PWA는 secure context 위에서 manifest·service worker·cache and update policy를 조합해 설치·오프라인·push 등 선택적 기능을 제공한다. service worker는 register·install·waiting·activate·fetch와 update 수명을 가지며 기존 page가 새 worker 적용 시점을 좌우한다.

서비스 워커 설치·갱신 생명주기registration, install and precache, waiting, activation and cleanup, controlled fetch strategies, update prompt, and safe fallback across old and new clientsREGISTER등록·갱신 확인secure context에서 sw.js 검사INSTALLINGinstall·precache필수 자원 저장 성공 여부INSTALLED · WAITING새 worker 대기기존 탭 유지·update 안내ACTIVATINGactivate·정리이전 cache 삭제·claim 정책REDUNDANT설치 실패·교체현재 worker는 계속 사용 가능CURRENT CLIENTS이전 active 유지열린 탭은 갑자기 교체하지 않음ACTIVATEDfetch 제어cache·network·offline 전략NEW sw.js FOUNDinstall 실패대기 중 공존탭 종료 또는 갱신 동의
  1. 1. 등록 또는 갱신 확인

    브라우저가 secure context에서 서비스 워커 스크립트를 가져와 기존 버전과 비교합니다.

  2. 2. Installing

    install 이벤트에서 필요한 자원을 precache하며 실패하면 새 worker는 redundant가 됩니다.

  3. 3. Installed · waiting

    이미 active worker가 제어하는 탭이 있으면 새 worker는 기다리고 앱은 update 안내를 보여줄 수 있습니다.

  4. 4. Activating

    기존 탭이 닫히거나 명시한 갱신 정책을 적용하면 activate에서 오래된 cache를 정리합니다.

  5. 5. Activated

    새 worker가 이후 client와 fetch를 제어하며 cache-first, network-first와 offline fallback 같은 전략을 수행합니다.

안전한 갱신

waiting worker가 있다는 이유만으로 열린 탭을 즉시 새 코드로 바꾸지 않습니다. 사용자 작업과 old/new asset 호환성을 확인해 적용 시점을 정합니다.

설치 실패의 fallback

새 worker 설치가 실패해도 이미 active인 worker와 현재 페이지는 계속 동작할 수 있어야 합니다.

PWA가 한 코드베이스로 모든 native 기능·플랫폼을 보장하거나 SEO를 자동 개선한다고 표현하지 않고 브라우저·OS별 설치와 push 지원 차이를 명시한다.


PWA 핵심 정리

핵심은 서비스 워커, 매니페스트, HTTPS를 기능 체크리스트가 아니라 배포 전략으로 함께 다루는 것입니다.

이번 장에서는 웹의 한계를 넘어 네이티브 앱과 같은 사용자 경험을 제공하는 PWA(Progressive Web App)에 대해 학습했습니다.

PWA의 개념과 서비스 워커(Service Worker), 웹 앱 매니페스트(Web App Manifest), HTTPS의 역할을 정리했습니다.

이 요소들이 오프라인 지원, 푸시 알림, 홈 화면 추가 기능과 어떻게 연결되는지도 함께 확인했습니다.

PWA는 오프라인 동작, 설치 가능성, 푸시 알림처럼 웹 앱의 사용성을 높이는 선택지입니다.

모든 웹 애플리케이션에 필요한 것은 아니므로, 서비스 특성과 사용자 환경에 맞춰 적용 여부를 판단해야 합니다.

PWA 흐름은 설치 가능성, 서비스 워커 요청 처리, 캐시 갱신을 배포 후 점검 루틴으로 연결해야 안정적으로 유지됩니다.