Starter Shape
The smallest maintainable PWA is a normal web app with a manifest, installable icons, a tiny service worker, and a clear offline promise.
Default Starter
public/
manifest.webmanifest
icons/
icon-192.png
icon-512.png
icon-maskable-512.png
offline.html
src/
main.ts
sw.ts
storage.ts
sync-queue.ts
index.html
Minimum Manifest
{
"id": "/",
"name": "Ledger PWA",
"short_name": "Ledger",
"description": "Offline-friendly ledger for small teams",
"start_url": "/",
"scope": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#0f172a",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "/icons/icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
Minimum Service Worker Promise
Start with this promise:
- The app opens after it has loaded once.
- Navigation falls back to
offline.htmlwhen the network is gone. - Static assets use versioned cache cleanup.
- User data lives in IndexedDB, not in service worker globals.
- Mutations are queued explicitly and replayed in foreground if Background Sync is unavailable.
Do not start with a complicated cache strategy matrix. Add runtime API caching only after you know which responses are safe to reuse.
Exclude From V1
- Store wrappers.
- Periodic Background Sync.
- Push notifications unless notifications are core to the product.
- Custom native bridges.
- Offline conflict resolution beyond a clear manual retry/export path.