How my 1.17 MB PWA updates itself without an app store (7-endpoint config fan-out + a strict service worker)
I build RKMovies, a small 4K media player that ships as a 1.17 MB Android APK and as a PWA on our own site. No Play Store means no update channel. So when we want to change a notice, a download link, or bump the version prompt, the app has to fetch config at runtime. Here is what we landed on in updater.js and sw.js. The config fan-out fetchConfig() fires 7 GET requests concurrently: raw.githubusercontent.com, cdn.jsdelivr.net, our own domain, a Cloudflare Pages mirror, rentry, paste.ee, and a local /config.json. Every request gets an AbortController with a 4-second timeout and cache: "no-store". A response only counts if it parses as JSON and has at least one of platforms, version, or notice. The point of 7 endpoints is that any single host can be blocked, slow, or wrong. If our domain is unreachable from some ISP, jsdelivr still answers. If GitHub raw is slow, the Pages mirror answers. We then compare all valid configs, take the highest latest_version, and prefer the platform-specific version (android vs desktop) over the top-level one. The winner gets written to localStorage, and if all 7 fail we boot from that cache instead of nothing. The service worker side sw.js precaches an 8-file shell (index, styles, app.js, adgate.js, updater.js, the ArtPlayer vendor bundle, the manifest) under a versioned cache name like rkmovies-shell-v43, then skipWaiting() + clients.claim() so the new shell takes over on next load. Fetch handling is network-first for same-origin static files, with one hard rule: code assets (app.js, style.css, vendor/, parts/) are only ever answered from an exact cache match. A new ?v= must never be served an old build, so a missed exact match returns a hard 503 instead of stale JS. Only non-code assets fall back to the cached shell with ignoreSearch. What this buys A 1.17 MB APK that can change its own download links, notices, and update prompts without a store release. The whole updater is one dependency-free file, and the config fetch is a plain GET of a static JSON file. No device ID, no analytics, no fingerprint. Update checks that don't track you are possible; we just had to make the "phone home" a dumb static file read. Play with it: the tiny native player I build, sideload the Android APK, or grab the Windows setup exe. Disclosure: I'm the developer of RKMovies. Size numbers come from the landing page's comparison table, not from marketing.
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to