최근 모바일 뷰에 대해 고민하면서 PWA 를 적용해보면 어떨까 하는 생각이 들어 PWA 를 공부해 보았습니다. 생각보다 자료가 알기 어려워서 정리할 겸 작성해봅니다.
Progressive Web App
정의는 애매모호하지만 Google 은 신뢰성있고, 빠르고, 매력적이어야 한다고(?) 표현함.
잘 구현한다면, 웹사이트만으로도 정말 APP같은 사용자 경험을 만들 수 있습니다.홈 화면에 아이콘을 추가할 수 있어 사용자를 묶어둘 수 있고(유저의 지속성을 유지할 수 있습니다)
설치 라는 허들을 한단계 낮춰서 도달율을 높일 수 있겠습니다.
PWA 의 실질적인 동작은 대부분 서비스 워커를 통해 구현되는것 같습니다.
그럼 서비스 워커의 특징에 대해 잠깐 알아보도록 하겠습니다.
서비스워커는, 다른 문서나 다른 소스로부터 발생되는 이벤트에 대응하기 위한 이벤트 드리븐 웹 워커라고 볼 수 있습니다(Push Notify 등).
다른 표준규격들이 웹에서 확장 가능하도록, 보편적 진입점(페이지 외에서 백그라운드 요소가 필요한것)을 제공합니다.
먼저 아무런 일도 하지 않는 서비스 워커를 만들어보도록 하겠습니다.
//serviceWorker.js
self.addEventListener('install', function(event) {
console.log("인스톨 되었다~")
}); // install 이 끝나면 인스톨되었다고 출력.
이런 서비스워커를 정의하고, index.js
에서 서비스 워커를 불러보도록 합니다.
//index.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/serviceWorker.js')
.then(registration => {
console.log('DONE_', registration)
})
.catch(e => {
console.log('SW registration failed: ', e)
})
})
}// load 가 끝나면 워커를 등록해줌.
저는 webpack 을 사용하고 있기 때문에, PWA 적용을 위해 workbox 웹팩 플러그인을 통해 해당 서비스 워커를 동작시켜보겠습니다.
yarn add -D workbox-webpack-plugin
workbox 는 PWA의 캐싱(caching) 기능을 편하게 구현할 수 있도록 지원되는 표준 PWA 라이브러리입니다.
해당 플러그인을 통해 웹팩 빌드해 줍니다.
///webpack.config
.
.
const workboxInject = new InjectManifest({
swSrc: './serviceWorker.js',
swDest:'serviceWorker.js'
})
.
.
plugins:[다른플러그인들~,workboxInject]
InjectManifest 함수는, 직접 설정한 서비스워커를 넣어줄 때 사용합니다.
generateSW 라는 함수도 존재하는데, 이는 간편하게 파일 캐싱용 서비스 워커를 생성할때 사용할 수 있습니다.
여기서는 직접 만든 서비스 워커를 사용했고, 추후에 서버 푸시를 받을 수 있도록 구현할것이기 때문에, InjectManifest 함수를 사용해 주었습니다.
웹팩 빌드를 해보면 서비스워커도 잘 등록되어있고, 콘솔에
인스톨 되었다~
도 잘 나오는 것을 확인할 수 있습니다.
pwa 어플리케이션을 만들기 위해 mainfest 설정도 해줘야합니다.
yarn add -D webpack-pwa-manifest
역시나 웹팩을 통해 빌드할것이므로 웹팩용 라이브러리를 받아줍니다.
{
"name": "PWA_DEMO",
"description": "FE STUDY PWA DEMO",
"background_color": "#ffffff",
"crossorigin": "use-credentials",
"short_name": "PWA",
}
웹팩 config 도 수정해줍니다.
const manifest = require('./manifest.json');
const manifestPlugin = new WebpackPwaManifest(manifest);
.
.
.
plugins:[manifestPlugin,workboxInject]
디버거의 Application 을 확인하면 Manifest 가 잘 들어가있는것을 확인할 수 있습니다.
아무 기능을 하지 않던 서비스워커를 확장해서, 서버 푸시를 받을 수 있도록 해봅시다.
//serviceWorker.js
import {skipWaiting,clientsClaim} from "workbox-core"
import {precacheAndRoute} from "workbox-precaching"
skipWaiting()
clientsClaim()
//푸시 이벤트 감지해서 보여주기
self.addEventListener('push', event => {
const title = '푸시테스트'
const options = {
body: event.data.text(),
}
event.waitUntil(
registration.showNotification(title, options)
)
})
// precacheAndRoute(self.__WB_MANIFEST) <- 안써주면 웹팩 빌드가 안된다....(why...)
skipWaiting
과 clientsClaim
이라는 새로운 함수가 보입니다. 서비스 워커는 최초 등록된 후 다음 로드시까지 이를 사용하지 않습니다.
하지만 skipWaiting
과 clientClaim
함수를 사용한다면, 해당 페이지를 즉시 제어하게 됩니다.
그리고 push
이벤트를 감지하여, 푸시가 왔을 때 푸시를 보여주도록 합니다.
`waitUntil`` 함수는, activate 한 이벤트를 기다려줍니다(push 나 fetch 같은)
serviceWorker
파일을 수정해주었으니. index.js
파일도 수정해야 합니다.
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/serviceWorker.js')
.then(reg => {
reg.pushManager.subscribe({
userVisibleOnly: true,
//applicationServerKey: 원래는 줘야함...
})
Notification.requestPermission()//푸시 허용할지 창 띄움
})
.catch(e => {
console.log('SW registration failed: ', e)
})
})
}
pushManager.subscribe
의 인자로 서버키를 줘야합니다. 그러기위해서 서버와 메시징 서비스가 필요한데요, 일반적으로는 구글의 파이어베이스 메시징 서비스를 사용합니다.
파이어베이스를 사용하여 웹 푸시를 보내기 위해서는, FCM 키와 공개키, 시크릿키가 필요합니다.
이것은 또 심오한 내용이기 때문에 다음 글에서 따로 다루도록 하겠습니다.
여기까지 설정해준다면, 서비스워커의 테스트 기능을 통해 푸시를 받아볼 수 있습니다.
그렇다면, workbox 를 사용하여 , 최초 데이터를 받아온 이후에 캐시하고,
오프라인상태에서 실행시켰을 때 사용할 수 있도록 구현해보겠습니다.
그 전에 캐싱 전략을 알아야 합니다. workbox 의 캐싱 전략은 아래와 같습니다.
캐시를 사용하기 위해서, serviceWorker 에 registerRoute 함수를 작성해주어야 합니다.
위에서 알아본 전략 중, 네트워크 퍼스트 전략을 사용해 보도록 하겠습니다.
먼저 네트워크에 요청을 보내본 뒤, 네트워크 응답이 없다면 캐시된 데이터를 대신 건내주는 전략이었죠.
//serviceWorker.js
.
.
registerRoute((req) => req.event.request
.headers
.get('accept')
.includes('text/html') //html 파일들을 캐싱
,new NetworkFirst());//네트워크 퍼스트 전략을 쓴다.
.
.
그리고 오프라인 상태를 만든 후, 새로고침을 해보면?
(서비스워커의 Offline 버튼을 눌러 오프라인 상태를 모킹할 수 있습니다)
짜잔 웹페이지가 정상적으로 불려오는것을 알 수 있습니다.
(콘솔창에 보시면, 네트워크 연결이 되지 않아서 에러가 뜨고있는것을 확인할 수 있습니다. 하지만 웹페이지는 정상적으로 불려옵니다.)
캐싱을 활용하는 방법도 여러가지인데요, 이것도 다다음글 정도에 작성해보도록 하겠습니다.
PWA 에 대해 간략하게 알아보았습니다.
공부하면서 생각보다 자료가 여기저기에 퍼져있어서 쉽지 않았던것 같네요,
도움이 되었으면 합니다.
더 좋은 글로 다시 돌아오겠습니다.
감사합니다.
선댓후감~ 좋은 글 감사합니다. ☺️