Skip to content

Instantly share code, notes, and snippets.

@HenriqueLimas
Created June 2, 2017 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save HenriqueLimas/f280307c00b3726c24cd8f31653c79c3 to your computer and use it in GitHub Desktop.
Save HenriqueLimas/f280307c00b3726c24cd8f31653c79c3 to your computer and use it in GitHub Desktop.

PWA

A lot of people think that native web its best than web

PWA they combine the best of the web with the best of the app

  • reliable (low connection)
  • fast (animation)
  • engagable (notificaiton, home screen)

Caching strategies

Why?

The web has easy access for user and devs. Simple A/B test, build. Fliboard increase +75%. Apps installation happen when you buy the phones. In other countries its a challange to update or install app. A sites don't have that. They add new capabilities. Who add 72%, and +26% users. Flipkart switch from app for a PWA. 2G network, with service worker they improve 3 times the loading.

What make it possible:

  • service worker
  • web manifest

Service worker

Its a progressive ehnacemnte and it works as a client side proxy. Apps can work offline. Push message it works with the service worker. Browser doens't need to be open.

Web app manifest

Control how the app apears to the users. And also how they can lunched.

PWA separate the content (change often) of the app-shell (don't change often).

App shell its the mnimimal HTML, CSS and JS that the user need to make the first view. The app shell its similar to the bundle code that we put on the app store. Service worker we can focus on speed. We can cache the app shell.

https://weather-pwa-sample.firebaseapp.com/final/index.html

We need to request AJAX.

  1. Break the design with the core components
  2. What needs to be on screen
  3. What other ui component for the app
  4. What supporting resource are needed (JS, css)

Server-Side Rendering The fastest one but harders

The easiest but the slowest method is to make AJAX requests

So, combination of both. The server inject the data into the apps insteado of pre-redering. THe server injects the data into the javascript.

Databases

Every app needs a way to store data. Maybe just user preference or differences relations.

Local storage

Its easy but its sync, this means that blocks render when we load it.

Caches

  • Easy to use
  • Async
  • Fast

But its transactional so it can be subscribed and its not supported.

Indexedb

  • Fast
  • Asyn
  • Fast

But its hard to use. But we can use localforage or lovefield.

Data its not permanent!!

====

Service worker

Is a JS it runs in your browser in the background. It listen to events from the browser or the server. It intercept fetch events. Proxy btw the network and the browns. They can serve offline or push notifications. In the future will support periodic sync.

** How does a service worker work (Create a graph)

  1. Web page register sw
  2. Installing (browser installed when its not instelled yet)
  3. Activated
  4. Idle (handle, fetch, push/message or terminated)

Service worker require HTTPS. Only localhost it works.

Intecepet network request, modify or redirect. HTTPS make that secure.

Registering:

if ('serviceWorker' in navigator) {
	// the scope is the entire root
	navigator.serviceWorker.register('/sw.js')
		.then();
}

Tips and tricks

  • Work on icognito.
  • chrome//serviceworker-internals
  • Application tab on chrome dev tools
  • All tabs on the same page use the same service worker. If one new sw is loaded, it will be idle until all the page refresh

When the sw is first register it triggers an install events. Great to pre-cache the resource needed in the app-shell.

var cacheName = 'weatherPWA-v1';
var filesToCache = [...] list of url

self.addEventListener('install', function(e) {
	e.waitUntil(
		caches.open(cacheName).then(function(cache) {
			return cache.addAll(filesToCache); //Atomic operation
		});
	);
})

The files that it already cached should be cleaned on the activated event

self.addEventListener('activate', function(e) {
	e.waitUntil(
		caches.keys().then(function(keyList) {
			return Promise.all(keyList.map(function(key) {
				if (key !== cacheName && key !== dataCacheName) {
					return caches.delete(key)
				}
			}))
		})
	)
})

Every change should update the cache.

Fetch events its used to low connection and no network.

self.addEventListener('fetch', function(e) {
	console.log('[ServiceWorker] Fetch', e.request.url);
	e.respondWith(
		caches.match(e.request).then(function (response) {
			return response || fetch(e.request);
		})
	)
})

Pay attention on update SW. The cache can never update.

Caching strategies

Cache First

Responde with first cache otherwise network

Ideal for common resourse. Key components for the App-shell.

Network first

Check network first and if it fails it try to field from cache. Its good for api request when you want the updated data. Ideal for content that are updated frequently. Pay attention on the network

Cache only

Resolve the request only in the cache. It garantee no network will be made to save battery

Network only

Fetch from network. Ideal for analytics and stuff that use only network

Cache and netwokr race

Request on both it responds with ever respond first. Always made a network request. If the network succed, the cache is updated.

Cache then network

Ideal for data that are updated frequently. Idea to show the cache and then update when the network respond. Pay attention to network dont' respond before the cache. Be careful using it with Data. This strategy say that network response is the source of truth. We need to kick of two parallale request. One for the cache and one for the network.

Its a good practies to separate the resources from the data api.

self.addEventListener('fetch', function(e) {
	if (dataApi) {
		e.respondWith(
			fetch(e.request)
				.then(function(response) {
					// Update cache with the new data
					return caches.open(dataCacheName).then(function(cache) {
						cache.puht(e.request.url, response.clone())
						return response;
					})
				})
		)
	} else {
		...
	}
})

sw-precache

Sometime using a lib can make thinkgs easier. Service pre-cache its node modules that automagically generating a service worker that pre-cache app-shell resources. Also we can configure run time caching options. We can use grunt or gulp or api. Advantage of automatically run every time you change a script.

npm install sw-precache
 swPrecache.write(<'service-worker.js'>, swOptions);
gulp.task('generate-sw', function () {
	var swOptions = {
		staticFileGlobs: [
			'./*.html',
			'./images/*.{png,svg,gif,jpg}',
			'./scripts/**/*.js',
			'./styles/**/*.css'
		],
		stripPrefix: '.',
		runtimeCaching: [{
			urlPattern: /^https:\/\/publicdata-weather\.firebaseio\.com/,
			handler: 'networkFirst',
			options: {
				cache: {
					name: 'weatherData'
				}
			}
		}]
	}
	
	return swPrecache.write('service-worker.js', swOptions);
})

PWA should be reliable fast and engagable.

PWA first class citizen

It can exists outside of the browser. Add to home screen. With an web manifest we can control how it will lunched. Its supported by chrome, opera and firefox.

WEb app manifest

Its a json to control how the app apears to user. And how it behaviors when its lunched. Supported on chrome and opera. It must contain the name and the short_name.

{
	name,
	short_name
	start_url: /index.html?hs=true,
	icons: [{
		src,
		sizes,
		
		
	}],
	background_color,
	theme_color,
	display,
	orientation
}

Images 48 96 128 144 192 256 384 512

Chrome use 48 and 128.

Validate the web manifest with the manifest validation (manifest-validator.appspot.com)

to use:

<link re=manifest href=manifest.json />

Web app Install Banners

Give the ability to quick and easy to add to home screen. Chrome it shows from some heuristics. It looks for:

  • service worker
  • web manifest
  • Engaged User (2 navigation for at least 5 minutes)

You can defer that. For example an ecommerce can defer it after the user buy something.

Mobile safari

Its different we can do same with meta tags.

<link rel="apple-touch-icon" sizes="" href="">

60 76 120 152 167 180

To hide the browser ui component

<meta name="apple-mobile-web-app-capable" content="yes">

minimize status bar

<meta name="apple-mobile-web-status-bar-style" content="black-translucent">

Needs to add some padding for the status bar be visible.

Deploy to an HTTPS Host

You must use HTTPS to register a sw.

GitHub pages, Firebase (automatically redirect) or Google AppEngine

To deploy to firebase:

firebase login
firebase init
firebase deploy

PWA combine the best of web and the best of APP, it use the great experience that app gives but published on the web.

What Next?

  • Offline course
  • Javascript Course
  • Push notifications
  • Web tooling and automation course
  • Web Payments API
  • Credential Manangement

PUsh notifications

onpush = function (event) {
	var data = event.data.json()
	var t = data.title
	var opt = {
		body: data.body,
		icon: data.icon,
		tag: data.tag
	}
	
	self.registration.showNotification(t, opt)
}
navigator.serviceWorker.register('sw.js')
	.then(function(reg) {
		reg.pushManager.getSubscription()
			.then(function(sub) {
				
			})
	})
navigator.serviceWorker.getRegistration().then(function(reg) {
	reg.pushManager.subscribe({userVisibleOnly: true})
		.thne(function(sub) {
			updateServiceWithSubstions(sub)
		})
}

githug/GoogleChrome/propel

subscriptions Object

{
	endpoint: "",
	keys: {
		auth: "",
		p256dh
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment