회사에서 업무용으로 만든 웹페이지를 PWA로 간단히 만들어 배포해보며 알게된 내용을 정리한다.
내가 만든 웹페이지가 PWA로 동작하기 위해서는 아래 3가지 요건을 모두 만족해야한다.
이번 글에서는 2,3 에 대해서 정리해두었다.
manifest 는 설치, 앱에 관한 구성정보를 담고있는 json 파일이다.
프로젝트 폴더에 manifest.json
파일을 생성하자.
{
"short_name": "프로젝트 이름(아이콘의 이름으로 표시됨)",
"name": "설치 배너에 표시되는 이름(검색의 키워드로 사용됨)",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "images/icon192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "images/icon512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"orientation": "portrait",
"theme_color": "#000000",
"background_color": "#ffffff"
}
icons
: 앱에서 필요한 다양한 크기의 아이콘. 앱의 스플래시 화면에서 쓰일 192px이상의 이미지 하나는 꼭 있어야 한다.start_url
: 필수요소로, 앱의 스플래시 화면 다음에 나올 페이지의 주소display
: 앱이 어떤 모양으로 보여질지 설정하는 값orientation
: 기기의 방향 (portrait : 세로, landscape : 가로)theme_color
: 브라우저 상단의 URL 입력바와 시스템바 까지 포함한 색상background_color
: 앱의 배경 색상.✅ 앱의 스플래시 화면은 background_color + icons + short_name 으로 구성된다.
<head>
<link rel="manifest" href="manifest.json">
</head>
서비스워커는 브라우저가 백그라운드에서 실행하는 스크립트로, 웹 과는 별개로 작동한다(웹과 상호작용 불가).
서비스 워커가 활성화 된 상태에서만 푸시알림, Fetch 등을 제어할 수 있다.
먼저, 프로젝트 폴더에 service_worker.js
라는 파일을 만든다.
그리고 index.html 에 연결된 메인 자바스크립트 파일에 service worker를 불러오는 구문을 추가한다.
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service_worker.js').then(() => {
console.log("서비스워커 등록됨")
})
}
event.waitUntil()
메소드를 사용해 기다릴 수 있다.설치가 완료되면 기존 서비스워커를 사용하는 클라이언트가 완전히 종료될 때 까지 대기하게 된다. (서비스워커 등록과정이면 대기 없이 전환됨)
여기서 self.skipWaiting()
를 사용해 기존 서비스워커 종료를 기다리지 않고 새 서비스워커를 활성화 할 수 있다.
self.addEventListener('install', event => {
event.waitUntil(...);
});
event.waitUntil()
로 기다릴 수 있음self.clients.claim()
로 열려있는 클라이언트를 다시 로드하지 않고 본 서비스워커가 바로 제어하게 할 수 있음서비스워커가 활성화 된 이후에는 Functional events 에 해당하는 이벤트를 핸들링하여 조작할 수 있다.(fetch, sync, push)
self.addEventListener('activate', event => {
event.waitUntil(...);
});
self.addEventListener('fetch', event => {
event.respondWith(...);
});
const cacheName ="cache123456";//캐시 이름 선언. 캐시 리스트 항목이 변경될 때 마다 cacheName을 변경해주어 이전에 사용했던 캐시를 지울 수 있도록 해야한다.
const cacheFiles = ['./','./index.html','./manifest.json', './test.png'];// 캐시할 리소스
//서비스워커 설치하고 캐시파일 저장
self.addEventListener('install', event => {
event.waitUntil(
caches
.open(cacheName)
.then(cache => {
// cacheName 에 addAll 메소드로 캐싱할 리소스를 다 넣어줌
return cache.addAll(cacheFiles);
})
.then(() => {
// 설치 후 바로 활성화 단계로 들어가게 해줌
return self.skipWaiting();
})
);
});
// 서비스워커 작동 시작(활성화)
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(key => {
// 불필요한 캐시는 삭제해줌 (현재 캐시와 이름이 다른 캐시 삭제)
return Promise.all(key.map(k => {
if(k !== cacheName) {
return caches.delete(k);
}
}))
})
)
});
// 어딘가에서 리소스를 가져올때 실행됨
// 데이터 요청시 네트워크 또는 캐시에서 찾아 반환
self.addEventListener('fetch', event => {
event.respondWith(
caches
.match(event.request)
.then(response => {
// 요청된 내용이 캐시에 있으면 캐싱한 데이터 제공, 아니면 fetch 시킴
return response || fetch(event.request)
}).catch(err =>
console.log(err)
)
);
});
사실 PWA와 서비스워커를 작성하는 방법은 더 다양하고 무궁무진하다.
내가 만든 페이지는 서버가 따로 없어서 푸쉬알림을 보내거나 어떤 요청을 처리하지는 못하지만, 전체적인 컨셉을 이해하고 바로 적용하기 위해 간단히 정리해보았다.
나중에 더 큰 프로젝트를 진행할때 제대로 PWA를 만들어 볼 수 있기를..!! 💨