Maxim Salnikov
@webmaxru
What is an offline-ready web application
Azure Developer Technical Lead at Microsoft
Browsers
JavaScript
Browsers
JavaScript
JS Engines
Browsers
JavaScript
JS Engines
UI Layer
Browsers
Community
JavaScript
JS Engines
UI Layer
Browsers
Community
JavaScript
JS Engines
UI Layer
Browsers
Issues?
Progressive web apps use modern web APIs along with traditional progressive enhancement strategy to create cross-platform web applications.
* but not everything**
** use progressive enhancement strategy
Exactly like native apps do! (or better)
My App
App
Service-worker
Browser/OS
Event-driven worker
Cache
fetch
push
sync
self.addEventListener('install', event => {
// Use Cache API to cache html/js/css
})
self.addEventListener('activate', event => {
// Clean the cache from the obsolete app shell versions
})
self.addEventListener('fetch', event => {
if (event.request.url.indexOf('/api') != -1) {
event.respondWith(
// Network-First Strategy (for API?)
)
} else {
event.respondWith(
// Cache-First Strategy (for app shell?)
)
}
})
# Installing the Workbox Node module
$ npm install workbox-build --save-dev
// We will use injectManifest mode
const {injectManifest} = require('workbox-build')
// Sample configuration with the basic options
var workboxConfig = {...}
// Calling the method and output the result
injectManifest(workboxConfig).then(({count, size}) => {
console.log(`Generated ${workboxConfig.swDest},
which will precache ${count} files, ${size} bytes.`)
})
// Sample configuration with the basic options
var workboxConfig = {
globDirectory: 'dist/',
globPatterns: [
'**/*.{txt,png,ico,html,js,json,css}'
],
swSrc: 'src/workbox-service-worker.js',
swDest: 'dist/sw.js'
}
// Importing Workbox itself from Google CDN
importScripts('https://googleapis.com/.../workbox-sw.js');
// Precaching and setting up the routing
workbox.precaching.precacheAndRoute([])
Caching, serving, managing versions
[
{
"url": "index.html",
"revision": "34c45cdf166d266929f6b532a8e3869e"
},
{
"url": "favicon.ico",
"revision": "b9aa7c338693424aae99599bec875b5f"
},
...
]
{
"scripts": {
"build-pwa": "npm run build-app &&
node workbox-build-inject.js"
}
}
A new version of the app is available. Click to refresh.
const updateChannel = new BroadcastChannel('app-shell');
updateChannel.addEventListener('message', event => {
// Inform about the new version & prompt to reload
});
workbox.precaching.addPlugins([
new workbox.broadcastUpdate.Plugin('app-shell')
]);
self.addEventListener('fetch', event => {
if (event.request.url.indexOf('/api/breakingnews') != -1) {
event.respondWith(
// Network-First Strategy
)
} else if (event.request.url.indexOf('/api/archive') != -1 {
event.respondWith(
// Cache-First Strategy
)
}
})
workbox.routing.registerRoute(
new RegExp('/api/breakingnews'),
new workbox.strategies.NetworkFirst()
);
workbox.routing.registerRoute(
new RegExp('/api/archive'),
new workbox.strategies.CacheFirst({
plugins: [...]
})
);
navigator.serviceWorker.ready.then( swRegistration => {
return swRegistration.sync.register('myFirstSync');
});
self.addEventListener('sync', event => {
if (event.tag == 'myFirstSync') {
event.waitUntil(
// Do useful things...
);
}
});
const postTweetPlugin =
new workbox.backgroundSync.Plugin('tweetsQueue', {
maxRetentionTime: 24 * 60 // Max retry period
})
workbox.routing.registerRoute(
/(http[s]?:\/\/)?([^\/\s]+\/)post-tweet/,
new workbox.strategies.NetworkOnly({
plugins: [postTweetPlugin]
}),
'POST'
)
const registration = await navigator.serviceWorker.ready;
await registration.backgroundFetch.fetch(
'my-series',
['s01e01.mpg', 's01e02.mpg'],
{
title: 'Downloading My Series',
downloadTotal: 1000000000
}
);
const bgFetches =
await registration.backgroundFetch.getIds();
console.log(bgFetches);
addEventListener('backgroundfetchsuccess', event => {
event.waitUntil(
(async function() {
try {
// Put the responses to Cache Storage
...
await event.updateUI({ title: `Downloaded!` });
} catch (err) {
await event.updateUI({ title: `Fail: ${err}` });
}
})()
);
});
"Progressive Web Apps State of the Union" by Dominick Ng at BlinkOn 10
Maxim Salnikov
@webmaxru
Maxim Salnikov
@webmaxru