Files
HealthLog/scripts/generate-sw-version.mjs
T
Marc-André Bombeck 60f587c5a7 fix(pwa): re-anchor the sw.js fallback version on every build
`public/sw.js` carries a `|| "..."` fallback literal used for `CACHE_VERSION`
when `importScripts('/sw-version.js')` is unavailable. The literal had drifted
to `v1.4.43`, four-plus minors behind `package.json`; in any environment where
the generated file is missing this keyed every cache to the stale version and
turned the activate-step eviction into a no-op — the exact bug the generator
was written to kill.

Extend the prebuild generator to rewrite the fallback literal in `sw.js` to the
current `package.json` version on every build, anchored on a
`/* @sw-version-fallback */` marker (the build fails loudly if the marker is
gone). The literal and the generated `sw-version.js` can no longer diverge.
The SW test now reads the fallback straight from the source so it tracks the
literal instead of hard-coding it.
2026-06-14 10:47:50 +02:00

57 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
/**
* v1.4.43 QoL (L3) — write the active package.json version into
* `public/sw-version.js`. The Service Worker (`public/sw.js`) loads
* this file via `importScripts('/sw-version.js')` and reads
* `self.__APP_VERSION__` to key its `CACHE_VERSION`.
*
* Pre-fix the SW carried a hand-bumped literal that drifted four
* releases stale; the `activate`-step's old-cache eviction became
* a no-op for every deploy in v1.4.38.4 → v1.4.42. Running this
* script as a `prebuild` step re-anchors the version on every build,
* so the eviction now fires reliably.
*
* Idempotent: writes the file unconditionally. Safe to commit the
* generated file or `.gitignore` it — either way `pnpm build` reruns
* the generator.
*/
import { readFileSync, writeFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(__dirname, "..");
const pkgPath = join(repoRoot, "package.json");
const outPath = join(repoRoot, "public", "sw-version.js");
const swPath = join(repoRoot, "public", "sw.js");
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
const version = `v${pkg.version}`;
const banner =
"// AUTO-GENERATED by scripts/generate-sw-version.mjs — do not edit.\n";
const body = `self.__APP_VERSION__ = ${JSON.stringify(version)};\n`;
writeFileSync(outPath, banner + body, "utf8");
// Also re-anchor the in-`sw.js` fallback literal to the current version, so
// the literal used when `/sw-version.js` is missing (dev, or a 404 on the
// generated file) can never drift stale — it bit v1.4.38.4 → v1.4.42. The
// `/* @sw-version-fallback */` marker is the rewrite anchor; the literal that
// follows it is replaced in place. If the marker is gone the SW source has
// been restructured and the build must surface that rather than silently skip
// the re-anchor.
const sw = readFileSync(swPath, "utf8");
const fallbackPattern = /(\/\* @sw-version-fallback \*\/\s*)"v[^"]*"/;
if (!fallbackPattern.test(sw)) {
process.stderr.write(
"generate-sw-version: @sw-version-fallback marker not found in public/sw.js\n",
);
process.exit(1);
}
const rewritten = sw.replace(fallbackPattern, `$1${JSON.stringify(version)}`);
if (rewritten !== sw) writeFileSync(swPath, rewritten, "utf8");
// One-line log so the build output shows the version we baked in.
process.stdout.write(`sw-version.js → ${version} (sw.js fallback re-anchored)\n`);