Slide 1

Slide 1 text

ARMAZENAMENTO OFFLINE APIS PARA PROGRESSIVE WEB APPS

Slide 2

Slide 2 text

@eduardojmatos eduardomatos.me OI, EU SOU O EDU

Slide 3

Slide 3 text

a maior plataforma de contratação de serviços do Brasil

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

VAMOS FALAR SOBRE INTERNET?

Slide 6

Slide 6 text

www.teleco.com.br/3G_cobertura.asp

Slide 7

Slide 7 text

http://www.teleco.com.br/4G_cobertura.asp

Slide 8

Slide 8 text

NETFLIX ISP SPEED INDEX

Slide 9

Slide 9 text

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/

Slide 10

Slide 10 text

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/

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

3 segundos era o “ponto ideal”

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

COMO ISSO DEVERIA IMPACTAR NOSSO DESENVOLVIMENTO?

Slide 15

Slide 15 text

PWA progressive web apps

Slide 16

Slide 16 text

Progressive Web Apps é a experiência do usuário ao alcance da web sendo Confiável, Rápida e Engajante.

Slide 17

Slide 17 text

TÁ, E COMO FAZ?

Slide 18

Slide 18 text

CONFIÁVEL • Carrega quase que instantaneamente; • Independe das condições de conexão com a internet; • Honestidade com relação à conectividade.

Slide 19

Slide 19 text

APPLICATION CACHE CACHE DE ARQUIVOS NO BROWSER

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

SERVICE WORKERS e

Slide 22

Slide 22 text

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); }); };

Slide 23

Slide 23 text

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)

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

CACHE API CACHE PROGRAMÁTICO DE ARQUIVOS NO BROWSER

Slide 26

Slide 26 text

// /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

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

ANTES DE SERVICE WORKERS DEPOIS DE SERVICE WORKERS

Slide 29

Slide 29 text

INTERCEPTAÇÃO DE REQUEST QUALQUER REQUEST PASSA PELO EVENTO DE FETCH

Slide 30

Slide 30 text

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')); }) }) ); });

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

RÁPIDA • JavaScript performático; • Interações fluídas e com sensação de velocidade; • Cache First.

Slide 34

Slide 34 text

document.write( '' ); JS PERFORMÁTICO https://developers.google.com/web/updates/2016/08/removing-document-write NOT • 38% de redução em conexão 2G; • 21% de redução até o first paint;

Slide 35

Slide 35 text

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!

Slide 36

Slide 36 text

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;

Slide 37

Slide 37 text

document.addEventListener( 'touchstart', onTouchStart, { passive: true }); INTERAÇÕES FLUÍDAS https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection

Slide 38

Slide 38 text

INTERAÇÕES FLUÍDAS https://www.youtube.com/watch?v=65VMej8n23A

Slide 39

Slide 39 text

CACHE FIRST self.addEventListener('fetch', event => { event.respondWith(caches.open('v1').then(cache => { return cache.match(event.request) .then(cached => { if (cached) return cached; //…

Slide 40

Slide 40 text

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' }] };

Slide 41

Slide 41 text

ENGAJANTE • Web App Manifest; • Push Notifications;

Slide 42

Slide 42 text

WEB APP MANIFEST

Slide 43

Slide 43 text

{ "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" }] }

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

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'); } }); });

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

NOTIFICAÇÕES

Slide 49

Slide 49 text

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.'); } }); }

Slide 50

Slide 50 text

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; }); }

Slide 51

Slide 51 text

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); });

Slide 52

Slide 52 text

NOTIFICAÇÕES https://tests.peter.sh/notification-generator https://web-push-book.gauntface.com/demos/notification-examples/

Slide 53

Slide 53 text

TESTE A NOTA DO SEU PWA

Slide 54

Slide 54 text

npm install -g lighthouse lighthouse https://www.google.com TESTE A NOTA DO SEU PWA

Slide 55

Slide 55 text

RESUMINDO…

Slide 56

Slide 56 text

JAVASCRIPT ❤ PWA

Slide 57

Slide 57 text

PWA É PROGRESSIVO USE E ABUSE PENSANDO QUE FOI FEITO PRA WEB TESTE SE AS API’S ESTÃO DISPONÍVEIS NO BROWSER

Slide 58

Slide 58 text

JABÁ http://bit.ly/design-patterns-2

Slide 59

Slide 59 text

JABÁ 2 http://bit.ly/pwa-js-2

Slide 60

Slide 60 text

@eduardojmatos http://eduardomatos.me eduardoj.matos@gmail.com OBRIGADO ;)