Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Armazenamento Offline: APIs para Progressive Web Apps

Armazenamento Offline: APIs para Progressive Web Apps

Algumas APIs de JavaScript que você já pode usar para que seu PWA funcione offline

Eduardo Matos

June 23, 2017
Tweet

More Decks by Eduardo Matos

Other Decks in Technology

Transcript

  1. 53% dos consumidores perdem a paciência e desistem de acessar

    o site após apenas três segundos. A expectativa do consumidor (afirmação feita por 79% dos entrevistados) é de encontrar as informações que deseja instantaneamente. http://exame.abril.com.br/marketing/quer-posicionar-bem-a-marca-entao-de-um-jeito-no-seu-site-movel/
  2. Mais da metade deles (56%) preferem comprar em sites móveis

    ou apps que permitem salvar preferências— entre consumidores entre 18 e 34 anos, esse número sobe para 64%. http://exame.abril.com.br/marketing/quer-posicionar-bem-a-marca-entao-de-um-jeito-no-seu-site-movel/
  3. 68% consideram 6 segundos um tempo de carregamento aceitável, mas

    que até 3 segundos era o “ponto ideal”. https://www.tecmundo.com.br/apps/81635-paciencia-brasileiro-apps-lentos-dura-somente-3-segundos.htm
  4. Progressive Web Apps é a experiência do usuário ao alcance

    da web sendo Confiável, Rápida e Engajante.
  5. CONFIÁVEL • Carrega quase que instantaneamente; • Independe das condições

    de conexão com a internet; • Honestidade com relação à conectividade.
  6. <html manifest="manifest.appcache"> CACHE MANIFEST # version 1 CACHE: http://jsexperience2017.imasters.com.br/images/logo.jpg http://jsexperience2017.imasters.com.br/palestrantes/01.jpg

    http://jsexperience2017.imasters.com.br/palestrantes/02.jpg NETWORK: https://facebook.com/sdk.js FALLBACK: index.html offline.html
  7. if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/js/sw.js') .then(reg => { if(reg.installing)

    { console.log('Service worker installing'); } else if(reg.waiting) { console.log('Service worker installed'); } else if(reg.active) { console.log('Service worker active'); } }).catch(error => { console.error('Registration failed with', error); }); };
  8. navigator.serviceWorker.register('/js/sw.js') .then(reg => { reg.addEventListener('updatefound', () => { const newServiceWorker

    = reg.installing; newServiceWorker.addEventListener('statechange', () => { if (newServiceWorker.state == 'activated') { console.info('SW is active!'); } }) }); }) .catch(error => error)
  9. // /js/sw.js self.addEventListener('install', event => { event.waitUntil( caches.open('v1').then(cache => {

    return cache.addAll([ '/index.html', '/js/app.js', '/css/styles.css', '/images/avatar/profile/01.jpg' ]); }) ); }); VERSIONAMENTO DE CACHE
  10. self.addEventListener('fetch', event => { event.respondWith(caches.open('v1').then(cache => { return cache.match(event.request) .then(cached

    => { if (cached) return cached; throw new Error('No cache founded'); }) .catch(error => { return fetch(event.request) .then(response => { cache.put(event.request, response.clone()); return response; }).catch(error => caches.match('offline.html')); }) }) ); });
  11. DOMAttrModified DOMAttributeNameChanged DOMCharacterDataModified DOMElementNameChanged DOMNodeInserted DOMNodeInsertedIntoDocument DOMNodeRemoved DOMNodeRemovedFromDocument DOMSubtreeModified JS

    PERFORMÁTICO https://developers.google.com/web/tools/lighthouse/audits/mutation-events NOT • Performance baixa! • Deprecated events!
  12. document.addEventListener('DOMContentLoaded', (event) => { navigator.geolocation.getCurrentPosition(success, error); Notification.requestPermission((result) => { resolve(result);

    }); }); EVITE JS PERFORMÁTICO https://developers.google.com/web/fundamentals/engage-and-retain/push-notifications/display-a-notification • Apenas use esses recursos quando o usuário precisar; • Exiba notificações somente quando necessário;
  13. CACHE FIRST self.addEventListener('fetch', event => { event.respondWith(caches.open('v1').then(cache => { return

    cache.match(event.request) .then(cached => { if (cached) return cached; //…
  14. CACHE FIRST npm i sw-precache -g sw-precache —config=precache-config.js --verbose USE

    SW-PRECACHE module.exports = { staticFileGlobs: [ 'app/css/**.css', 'app/**.html', 'app/images/**.*', 'app/js/**.js' ], stripPrefix: 'app/', runtimeCaching: [{ handler: 'cacheFirst' }] };
  15. { "name": "Offline App Presentation", "short_name": "OfflineAPp", "start_url": ".", "display":

    "standalone", "background_color": "#fff", "description": "Testing our Offline App Presentation", "icons": [{ "src": “images/touch/icon-168.png", "sizes": "168x168", "type": "image/png" }], "related_applications": [{ "platform": "web" }, { "platform": "play", "url": "https://play.google.com/store/apps/details?id=offapp" }] }
  16. window.addEventListener('beforeinstallprompt', function(e) { e.userChoice.then(function(choiceResult) { console.log(choiceResult.outcome); if(choiceResult.outcome == 'dismissed') {

    console.log('Sad, but user cancelled home screen install'); } else { console.log('Yes! User added to home screen'); } }); });
  17. WEB APP MANIFEST • Ter um web app manifest com:

    • short_name (usado na home screen); • name (usado no banner de instalação); • um ícone png de 144x144; • “start_url” que o app é carregado. • Ter um service worker registrado em seu site; • Servido com HTTPS (pra usar Service Worker isso já é um requisito); • Foi visitado pelo menos duas vezes, em pelo menos 5 minutos entre as visitas CRITÉRIOS PRA EXIBIÇÃO DO BANNER DE INSTALAÇÃO DO WEB APP
  18. function askPermission() { return new Promise((resolve, reject) => { const

    permissionResult = Notification.requestPermission((result) => { resolve(result); }); if (permissionResult) { permissionResult.then(resolve, reject); } }) .then((permissionResult) => { if (permissionResult !== 'granted') { throw new Error('Fail on granted permission.'); } }); }
  19. function subscribeUserToPush() { return getSWRegistration() .then((registration) => { const subscribeOptions

    = { userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array( 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9- SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U' ) }; return registration.pushManager.subscribe(subscribeOptions); }) .then((pushSubscription) => { console.log('Received: ', JSON.stringify(pushSubscription)); return pushSubscription; }); }
  20. self.addEventListener('push', function(event) { const promiseChain = self.registration.showNotification( 'Hello, World.', {

    body: 'notification test!', icon: '/images/icon-512x512.png', image: '/images/body-notification.jpg', vibrate: [ 500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500 ], sound: 'starWarsPing.mp3' } ); event.waitUntil(promiseChain); });
  21. PWA É PROGRESSIVO USE E ABUSE PENSANDO QUE FOI FEITO

    PRA WEB TESTE SE AS API’S ESTÃO DISPONÍVEIS NO BROWSER