7. Mobile website 의 장단점
• 장점
• URL! - 빠른 배포, 연결성
• 보유 컨텐츠/서비스를 모바일 기기에 빠르게 배포
• 표준 기반으로 다양한/폭넓은 기기 지원
• 단점
• Native 대비 떨어지는 UX
• 성능
• 기능들
Manifest + Service Worker + Push
Service Worker + AMP + Rendering optimization efforts
Extending web platform continued
11. Case study: Washingtonpost PWA
“In our public-facing beta of the PWA web app, we’ve seen about
5x engagement – page views per visit, number of stories read,”
Washington Post’s head of product tells Beet.TV in this video
interview.
Source: http://www.beet.tv/2016/09/wapopwamarburger.html
25. Dedicated worker
Run job.js
t
* Lifetime is bound to the document
unless .terminate is called.
Lifetime bound to their parent
Lifetime of Dedicated Worker
new Worker(‘job.js’)
26. Run sw.js
Browser internal
t
Service worker
Term
inate
Start
onfetch
e.waitUntil()
push
Term
inate
Start
onpush
e.waitUntil()
fetch
Lifetime of Service Workers
Intentionally short lifetime
<img src=‘pic.png’>
27. Service Worker 활용을 위한 주요 개념
• Install: Register - Update - Unregister
• Client matching - Navigation 포함 메인 리소스 fetch 시 service worker 결정
• Functional event handling
• fetch, push, notificationclick, sync, etc.
• Caching
• Pre-cache - oninstall 이벤트 처리
• Dynamic-cache - onfetch에서 활용
• Serve on HTTPS
• Fetch API 와 Streams API 를 주목하자
28. Register - Update - Unregister
Service Worker Lifecycle
navigator.serviceWorker.register(‘sw.js’, { scope: ‘./‘ });
self.addEventListener('install', e => {
// Cache static resources
});
Registration - scope: ‘./‘
installing waiting active
self.addEventListener('activate', e => {
// Delete cache, etc.
});
self.addEventListener('fetch', e => {
// respondWith cached resource, etc.
});
self.addEventListener('push', e => {
// showNotification etc.
});
Wait until
- No client uses active worker
- skipWaiting() was called
install
fetch
push
activate
29. Register - Update - Unregister
Service Worker Lifecycle
self.addEventListener('install', e => {
// Cache static resources
});
Registration - scope: ‘./‘
installing waiting active
self.addEventListener('activate', e => {
// Delete cache, etc.
});
self.addEventListener('fetch', e => {
// respondWith cached resource, etc.
});
Wait until
- No client uses active worker
- skipWaiting() was called
install
fetch
activate
registration.update();
30. Register - Update - Unregister
Service Worker Lifecycle
Registration - scope: ‘./‘
installing waiting active
Wait until
- No client uses active worker
- No service worker is serving events
registration.unregister();
unregister flag
31. “/bar” /bar/sw1.js
[ Registration map ]
Scope Script URL
“/foo” /foo/sw.jsFrom page
var sw = navigator.serviceWorker;
① sw.register('/bar/sw1.js', { scope: '/bar' });
② sw.register('/foo/sw.js', { scope: '/foo' });
③ sw.register('/bar/sw2.js', { scope: '/bar' } );
Registrations
“/bar” /bar/sw2.js
32. onfetch
sw.js
Cache
Attempt to match cache
Matched response
Respond to client
“/” /sw.js
[ Registration map ]
Scope Script URL
“/foo” /foo/sw.js
Doc
Navigate https://example.com/index.html
fetch event
Scope matching
Run SW
Client matching
Navigation / Worker client creation
33. onfetch
sw.js
Cache
Attempt to match cache
Matched response
Respond to client
“/” /sw.js
[ Registration map ]
Scope Script URL
“/img” /img/sw.js
Doc
Fetch “https://example.com/img/flower.png
fetch event
Control
Run SW
Subresource requests
메인 리소스 내부에서 발생하는 서비 리소스에 대한 fetch 요청들
36. document.querySelector('.cache-article').addEventListener('click', function(event) {
event.preventDefault();
var id = this.dataset.articleId;
caches.open('mysite-article-' + id).then(function(cache) {
fetch('/get-article-urls?id=' + id).then(function(response) {
// /get-article-urls returns a JSON-encoded array of
// resource URLs that a given article depends on
return response.json();
}).then(function(urls) {
cache.addAll(urls);
});
});
});
https://jakearchibald.com/2014/offline-cookbook/#on-user-interaction
Service Worker 사용 패턴
Cache on user demand
39. https://jakearchibald.com/2014/offline-cookbook/#on-push-message
self.addEventListener('push', function(event) {
if (event.data.text() == 'new-email') {
event.waitUntil(
caches.open('mysite-dynamic').then(function(cache) {
return fetch('/inbox.json').then(function(response) {
cache.put('/inbox.json', response.clone());
return response.json();
});
}).then(function(emails) {
registration.showNotification("New email", {
body: "From " + emails[0].from.name
tag: "new-email"
});
})
);
}
});
self.addEventListener('notificationclick', function(event) {
if (event.notification.tag == 'new-email') {
// Assume that all of the resources needed to render
// /inbox/ have previously been cached, e.g. as part
// of the install handler.
clients.openWindow(‘/inbox/');
}
});
Service Worker 사용 패턴
onpush