From 6791d611f0bf263d68c7b9161e346634610275b9 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Wed, 21 Oct 2026 20:20:41 -0400 Subject: [PATCH] =?UTF-8?q?fix(vite):=20guard=20cleanStaleChunks=20?= =?UTF-8?q?=E2=80=94=20vp=20test=20deleted=20every=20built=20chunk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cleanStaleChunks plugin lives in the shared vite config, so its closeBundle hook also fired under `vp test` — where generateBundle never runs, produced stayed empty, and the sweep deleted every hashed chunk in web/static (28 files → 3). The entries still referenced their old imports, so every page 404'd and Alpine never started: the whole reader and media system appeared dead after merely running the test suite. Guard: skip the sweep when produced.size === 0 — not a build run, no build output to clean. Verified: build → 28 files, test → 28 files; back-to-back builds stay byte-identical. --- vite.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vite.config.ts b/vite.config.ts index 1b8edb37..6125d39e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,6 +19,13 @@ const pdfjsAssets = () => ({ // so hashed chunks from previous builds would otherwise accumulate // forever and leak into Docker images via the build context. Remove // any *-.js/.css/.mjs(.map) that this build did not produce. +// +// The produced.size === 0 guard is load-bearing: this config also drives +// `vp test`, and vitest runs closeBundle with generateBundle never having +// fired — an empty produced set means "not a build run", and sweeping +// then deleted every live chunk (the 2026-10-21 incident where +// `npm run test` gutted web/static down to the three entry files and +// every page 404'd its imports). const cleanStaleChunks = () => { const produced = new Set(); return { @@ -27,6 +34,7 @@ const cleanStaleChunks = () => { for (const fileName of Object.keys(bundle)) produced.add(fileName); }, closeBundle() { + if (produced.size === 0) return; const outDir = "web/static"; const chunkRe = /-[A-Za-z0-9_-]{8}\.(js|css|mjs)(\.map)?$/; for (const f of readdirSync(outDir)) {