Maxim Salnikov
@webmaxru
How to build a framework-agnostic PWA?
Azure Developer Relations Lead at Microsoft
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
SW library
Out-of-the-box
Configuring
Extending
Web App Manifest
App Shell
$ create-react-app my-react-pwaserviceWorker.unregister();serviceWorker.register();SW library
Out-of-the-box
Configuring
Extending
Web App Manifest
App Shell
Runtime Caching
$ vue add pwaSW library
Out-of-the-box
Configuring
Extending
Web App Manifest
App Shell
Runtime Caching
Push Notifications
Update Flow
$ ng add @angular/pwaMy 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...
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
// 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-pwa": "npm run build-app &&
                  node workbox-build.js"
  }
}App build files
App shell file list
Service worker file
// App shell
workbox.precaching.precacheAndRoute([])
// Runtime caching
workbox.routing.registerRoute(
  /(http[s]?:\/\/)?([^\/\s]+\/)api/,
  workbox.strategies.networkFirst()
)
// Push notifications
self.addEventListener('push', (event) => {...})if ('serviceWorker' in navigator) {
    navigator.serviceWorker
        .register('/service-worker.js')
}There is a new version of the app is available. Click here to refresh.
import { Workbox } from 'workbox-window'
// For Angular
platformBrowserDynamic().bootstrapModule(AppModule)
  .then( () => {
    if ('serviceWorker' in navigator) {
      const wb = new Workbox('service-worker.js');
      // Event listeners...
      wb.register();
    }
  })$ npm install workbox-windowwb.addEventListener('installed', event => {
  if (event.isUpdate) {
  // Show "Newer version is available. Refresh?" prompt
  } else {
  // Optionally: show "The app is offline-ready" toast
  }
});
workbox.core.skipWaiting()
workbox.core.clientsClaim()Maxim Salnikov
@webmaxru