Maxim Salnikov
@webmaxru
What is an offline-ready web application
Developer Audience 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
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 versions
})
self.addEventListener('fetch', event => {
// Serve assets from cache or network
})
# Installing the Workbox Node module
$ npm install workbox-build --save-dev
// 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'
}
import { precacheAndRoute } from "workbox-precaching";
// Precaching and setting up the routing
precacheAndRoute(self.__WB_MANIFEST)
Caching, serving, managing versions
// 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.`)
})
{
"scripts": {
"build-sw": "node workbox-build.js && npx rollup -c",
"build": "npm run build-app && npm run build-sw"
}
}
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
)
}
})
import { registerRoute } from "workbox-routing";
import * as strategies from "workbox-strategies";
registerRoute(
new RegExp('/api/breakingnews'),
new strategies.CacheFirst()
);
registerRoute(
new RegExp('/api/archive'),
new strategies.CacheFirst({plugins: [...]})
);
navigator.serviceWorker.ready.then( swRegistration => {
return swRegistration.sync.register('postTweet');
});
self.addEventListener('sync', event => {
if (event.tag == 'postTweet') {
event.waitUntil(
// Do useful things...
);
}
});
import {BackgroundSyncPlugin} from 'workbox-background-sync';
const postTweetPlugin =
new BackgroundSyncPlugin('tweetsQueue', {
maxRetentionTime: 24 * 60 // Max retry period
})
registerRoute(
/(http[s]?:\/\/)?([^\/\s]+\/)post-tweet/,
new strategies.NetworkOnly({plugins: [postTweetPlugin]}),
'POST'
)
const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
try {
registration.periodicSync.register('refreshTweets', {
// An interval of one day.
minInterval: 24 * 60 * 60 * 1000,
});
} catch (error) {
// PBS cannot be used.
}
}
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'refreshTweets') {
event.waitUntil(
fetchNewTweets() // Maybe
);
}
});
Maxim Salnikov
@webmaxru
Maxim Salnikov
@webmaxru