앱 없이 PWA로 모바일 서비스 만들기
앱 스토어에 올리려면 심사 대기에 수수료까지 — 번거롭고 비용도 만만치 않죠. **PWA(Progressive Web App)**는 이런 불편함을 해소해 줍니다. 웹 기술만으로 네이티브 앱 수준의 경험을 제공하면서, 설치, 오프라인, 푸시 알림까지 지원합니다.
PWA란 무엇인가?
PWA는 HTML, CSS, JavaScript 표준 웹 기술로 만들어졌지만, 모바일 앱처럼 동작하는 웹 애플리케이션입니다. 2015년 구글이 처음 개념을 제시했고, 현재는 Chrome, Safari, Edge, Firefox 등 주요 브라우저 모두에서 지원합니다.
| 특징 | 네이티브 앱 | PWA |
|---|---|---|
| 설치 경로 | 앱 스토어 | 브라우저에서 바로 |
| 업데이트 | 사용자 수동 설치 | 자동 (서버 배포만으로) |
| 개발 비용 | iOS + Android 각각 | 한 번만 개발 |
| SEO | 불가 | 가능 (URL 기반) |
| 오프라인 지원 | 가능 | 가능 (Service Worker) |
| 앱 스토어 수수료 | 15~30% | 없음 |
PWA의 3가지 핵심 요소
1. HTTPS
Service Worker는 보안 연결에서만 작동합니다. localhost는 예외로 허용되므로 개발 단계에서는 로컬에서 테스트 가능합니다. 배포 시에는 반드시 HTTPS를 적용하세요.
2. Web App Manifest
PWA를 홈 화면에 설치할 수 있게 해주는 JSON 설정 파일입니다.
{
"name": "내 서비스",
"short_name": "서비스",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#38bdf8",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
HTML head 태그에 연결하면 됩니다:
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#38bdf8">
display: standalone— 브라우저 UI 없이 앱처럼 실행start_url— 앱 실행 시 시작 페이지icons— 홈 화면 아이콘 (192px, 512px 필수)
3. Service Worker
백그라운드에서 실행되는 JavaScript 파일로, 네트워크 요청을 가로채 캐싱 및 오프라인 지원을 담당합니다.
Service Worker 구현 단계별 가이드
Step 1: 등록 (메인 JS에 추가)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(reg => console.log('SW 등록 성공:', reg.scope))
.catch(err => console.error('SW 등록 실패:', err));
});
}
페이지 로드 완료 후 등록해야 초기 로딩 속도에 영향을 주지 않습니다.
Step 2: 설치 및 캐싱 (service-worker.js)
const CACHE_NAME = 'my-app-cache-v1';
const ASSETS = [
'/',
'/index.html',
'/styles.css',
'/app.js',
'/offline.html'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
console.log('캐시 저장 중...');
return cache.addAll(ASSETS);
})
);
});
Step 3: 네트워크 요청 가로채기
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
if (cached) return cached;
return fetch(event.request)
.then(response => {
const copy = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, copy);
});
return response;
})
.catch(() => caches.match('/offline.html'));
})
);
});
Step 4: 구버전 캐시 정리
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(
keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))
)
)
);
});
캐싱 전략 비교
PWA 캐싱은 서비스 특성에 맞게 전략을 선택해야 합니다.
Cache First (캐시 우선)
정적 자원(이미지, CSS, JS)에 적합합니다. 캐시에서 먼저 응답하고, 없으면 네트워크를 사용합니다. 속도는 빠르지만 콘텐츠 업데이트가 느릴 수 있습니다.
Network First (네트워크 우선)
실시간 데이터(뉴스 피드, API 응답)에 적합합니다. 네트워크를 먼저 시도하고, 실패하면 캐시를 사용합니다. 항상 최신 데이터를 제공하지만 오프라인 상황에서는 캐시 데이터를 보여줍니다.
Stale-While-Revalidate
캐시된 응답을 즉시 보여주면서 백그라운드에서 새 버전을 받아옵니다. 속도와 최신성을 모두 잡을 수 있는 균형 잡힌 전략입니다.
Vite + React 프로젝트에 PWA 적용하기
Vite를 사용한다면 vite-plugin-pwa로 손쉽게 설정할 수 있습니다.
npm install -D vite-plugin-pwa
// vite.config.js
import { VitePWA } from 'vite-plugin-pwa';
export default {
plugins: [
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: '내 앱',
short_name: '앱',
theme_color: '#38bdf8',
icons: [
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' }
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg}']
}
})
]
};
빌드 시 manifest.json과 service-worker.js가 자동 생성됩니다.
설치 배너 직접 제어하기
브라우저의 자동 설치 배너 대신 직접 타이밍을 제어할 수 있습니다.
let deferredPrompt;
window.addEventListener('beforeinstallprompt', e => {
e.preventDefault();
deferredPrompt = e;
document.getElementById('install-btn').style.display = 'block';
});
document.getElementById('install-btn').addEventListener('click', async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log('사용자 선택:', outcome);
deferredPrompt = null;
});
원하는 시점(온보딩 완료 후, 특정 기능 사용 후 등)에 설치를 유도할 수 있어 전환율을 높일 수 있습니다.
PWA 품질 검사: Lighthouse
Chrome DevTools의 Lighthouse를 활용해 PWA 점수를 측정할 수 있습니다.
- Chrome DevTools (F12) 열기
- Lighthouse 탭 선택
- Progressive Web App 체크 후 분석 실행
체크 항목:
- HTTPS 적용 여부
- Service Worker 등록 여부
- manifest.json 유효성
- 오프라인 동작 여부
- 아이콘 및 splash screen 설정
언제 PWA가 적합한가?
PWA가 특히 빛을 발하는 상황이 있습니다:
- MVP 단계 스타트업: 앱 개발 비용 없이 빠른 검증 가능
- 콘텐츠 중심 서비스: 블로그, 뉴스, 커머스 등
- B2B 내부 툴: 앱 스토어 심사 없이 직원에게 배포
- 글로벌 서비스: 저사양 기기나 불안정한 네트워크 환경에서도 원활한 경험
반면 카메라, 블루투스, NFC 등 하드웨어 제어가 핵심인 서비스라면 네이티브 앱이 더 적합합니다. 다만 WebRTC, Web Bluetooth 등 웹 API의 발전으로 그 격차는 빠르게 좁혀지고 있습니다.
마무리
PWA는 진입 장벽이 낮으면서도 강력한 모바일 경험을 제공합니다. manifest.json 하나와 service-worker.js 몇십 줄로 시작할 수 있고, 기존 웹사이트에도 점진적으로 적용할 수 있습니다.
코드벤터는 스타트업과 1인 개발자가 최소한의 비용으로 최대한의 사용자 경험을 만들 수 있도록, PWA 설계부터 배포까지 실전 기반의 개발 인사이트를 지속적으로 공유합니다.