Download the whole app build behind a loading page

In production, a page request without the running build's cookie gets a
small loading page instead of the app. It downloads every file in
.bunext/public (listed at /build-info.json) into that build's cache,
checks they are all there, hands over to a new service worker waiting
behind an older one, sets the cookie and reloads. The service worker
then serves the app's code from the cache, so later visits load it from
the device.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-20 19:33:15 +01:00
co-authored by Claude Opus 5.5
parent 9778d0b9ff
commit b3057119df
16 changed files with 991 additions and 45 deletions
@@ -0,0 +1,63 @@
import path from "path";
import { AppData } from "@/src/data/app-data";
import { PwaLoadingPath } from "@/src/data/pwa-data";
import { getCookie } from "@/src/utils/cookies";
import needsPrecachePage from "@/src/utils/needs-precache-page";
import grabPrecacheManifest from "./grab-precache-manifest";
const LOADING_PAGE = path.join(
path.resolve(import.meta.dir, "../../../../public"),
PwaLoadingPath,
);
/**
* The placeholder `public/loading.html` carries for the running build.
*/
const BuildPlaceholder = "{{build}}";
/**
* Production only: a browser opening a page without the running build in
* its cookie gets the loading page in its place, at the same address. The
* page downloads the build's `.bunext/public` files into the build's
* cache, checks they are all there, sets the cookie and reloads, and the
* service worker then serves the app's code from the device. Null lets
* the request through.
*/
export default async function handlePrecacheGate({
req,
url,
}: {
req: Request;
url: URL;
}): Promise<Response | null> {
const manifest = grabPrecacheManifest();
const needs_page = needsPrecachePage({
method: req.method,
pathname: url.pathname,
fetch_mode: req.headers.get("Sec-Fetch-Mode"),
fetch_dest: req.headers.get("Sec-Fetch-Dest"),
accept: req.headers.get("Accept"),
cookie_build_id: getCookie(req, AppData["BuildCookieName"]),
build_id: manifest?.build_id,
});
if (!needs_page || !manifest) return null;
const file = Bun.file(LOADING_PAGE);
if (!(await file.exists())) return null;
const build = JSON.stringify({
build_id: manifest.build_id,
total: manifest.files.length,
}).replace(/</g, "\\u003c");
return new Response((await file.text()).replace(BuildPlaceholder, build), {
headers: {
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "no-store, max-age=0, must-revalidate",
"X-Content-Type-Options": "nosniff",
},
});
}