compose-wasmjs-pwa

Turning a Compose Multiplatform wasmJs app into a PWA with deliberate software updates and a correctly separated data cache — the files, ready to copy.

This is the companion bundle to the article Shipping a Kotlin Compose Multiplatform app as a PWA. The article argues the why; these are the files that implement it.

You do not need Claude Code to use this.

It is packaged as a skill for Claude Code, because that is how it was built and applied to a real production app. Ignore that framing and what remains is a folder of plain files with {{PLACEHOLDER}} markers, plus prose you can read straight through: SKILL.md works as an ordinary step-by-step guide.

If you do use Claude Code, drop this folder into .claude/skills/ and it will run the conversion, ask which update notification you want, and audit an existing data layer against the checks in Phase B.

Start here

SKILL.md The procedure, end to end: retiring an older service worker, precaching, the startup gate, the update notification, then the data-layer audit and the server headers.
references/how-it-works.md Why the update flow is built the way it is — the startup gate, why intent is captured at updatefound, and how to reach clients stuck behind an old cache-first worker.
references/data-and-deployment.md The caching model, offline behaviour, the server cache headers, and the verification checklist.
references/notification-styles.md The four update-notification styles and their trade-offs, plus how a server-driven minimum-version gate differs from all of them.

Web assets

registerServiceWorker.js Registration, the startup gate that stops the old version flashing up, and the deferred-activation logic behind the “New Software” affordance.
workbox-config-for-wasm.js Precaches the software and nothing else — deliberately no runtimeCaching.
legacy-sw-tombstone.js Retires a previously deployed hand-written worker, including clients that can no longer load your new page.
index.html · manifest.json Page shell with the splash element, and the web app manifest.

Kotlin assets

PwaUpdate.*.kt The expect/actual bridge between the service worker and Compose — common, wasmJs, no-op for other targets.
app-update-ui.kt The pulsating button and confirm dialog.
offline-indicator.kt Data-status indicator variants; pick one and delete the rest.
Store.*.kt An app-owned data cache for projects that have none — common, wasmJs (Cache API), jvm (files), memory. Most apps should keep what they already have.
data-poll-template.kt The conditional-GET request shape, worth reading even if you keep your own layer.
wasmJs-main.kt The main() that awaits the startup gate before mounting Compose.

Build wiring

gradle-wiring.md Version-catalog entries and the plugin to apply.
scripts/latest_version.sh Resolves the newest published version of a plugin or artifact, so nothing is hardcoded.

Validated 2026-07-25 against Kotlin 2.4.10, Compose Multiplatform 1.11.1, Gradle 9.5.1, Ktor 3.5.1, Workbox 7.4.0 and the ComposePWA plugin 0.7.0-alpha03, by converting a real production app and deploying it.

A few claims are pinned to those versions and deserve re-checking if you are far from them: the JsException behaviour of a failed fetch, the cleanupOutdatedCaches predicate, and anything about the plugin, which is a 0.x alpha. SKILL.md says which, and why.