Maxim Salnikov
@webmaxru
What is an offline-ready web application
Developer Audience Lead at Microsoft
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