AI Skill Library

PWA & Service Worker

Manifest, service worker lifecycle, caching strategies, offline, push notifications.

pwaservice-workerfrontendweb
# PWA & Service Worker

## Web App Manifest
```json
{
  "name": "My App",
  "short_name": "App",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#000000",
  "icons": [
    { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
  ]
}
```
```html
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#000000">
```

## Service Worker lifecycle
Install -> Activate -> Fetch/Sync/Push
```js
// sw.js
self.addEventListener('install', e => {
  e.waitUntil(
    caches.open('v1').then(c => c.addAll(['/','/','/app.css','/app.js']))
  )
  self.skipWaiting()
})
self.addEventListener('activate', e => {
  e.waitUntil(caches.keys().then(keys =>
    Promise.all(keys.filter(k => k !== 'v1').map(k => caches.delete(k)))
  ))
  self.clients.claim()
})
```

## Caching strategies
- **Cache First**: serve from cache, fallback to network. Best for static assets.
- **Network First**: try network, fallback to cache. Best for API data.
- **Stale While Revalidate**: serve cache immediately, update in background.
- **Network Only**: no caching (e.g. analytics).

```js
self.addEventListener('fetch', e => {
  if (e.request.url.includes('/api/')) {
    // Network first
    e.respondWith(
      fetch(e.request).then(res => {
        const clone = res.clone()
        caches.open('api').then(c => c.put(e.request, clone))
        return res
      }).catch(() => caches.match(e.request))
    )
  } else {
    // Cache first
    e.respondWith(caches.match(e.request).then(r => r || fetch(e.request)))
  }
})
```

## Register from app
```js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(reg => console.log('SW registered', reg.scope))
  })
}
```

## Workbox (recommended for production)
```bash
npm install workbox-webpack-plugin
# or with Vite:
npm install vite-plugin-pwa
```
```js
// vite-plugin-pwa config
VitePWA({
  strategies: 'injectManifest',
  workbox: {
    globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
    runtimeCaching: [{
      urlPattern: /\/api\//,
      handler: 'NetworkFirst',
      options: { cacheName: 'api-cache', expiration: { maxAgeSeconds: 86400 } },
    }],
  },
})
```

## Push notifications
```js
const sub = await reg.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY),
})
await fetch('/api/subscribe', { method: 'POST', body: JSON.stringify(sub) })
```

API: /api/skills/pwa-service-worker