fix(spa): self-heal stale clients after deploys (vite:preloadError + cache headers)
After a release the old hashed chunks are deleted, so an open tab from the previous build failed its next lazy-page import until a manual refresh. Three-part fix per the Vite deploy guide: - vite:preloadError listener reloads the page once (10s sessionStorage guard against loops) so stale tabs heal themselves - static cache headers: /assets/* immutable for a year (content-hashed names), index.html no-cache so new visits always see fresh chunk refs - missing /assets/* now 404 instead of getting the SPA index.html fallback (HTML-as-JS masked the failure) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -206,12 +206,30 @@ async function start() {
|
||||
root: path.join(__dirname, "..", "dist-client"),
|
||||
prefix: "/",
|
||||
wildcard: false,
|
||||
// Deploy-skew caching contract (per the Vite deploy guide):
|
||||
// - /assets/* names are content-hashed → safe to cache forever
|
||||
// (a changed file always gets a NEW name, so "immutable" is correct).
|
||||
// - index.html (and any non-hashed file) must always be revalidated,
|
||||
// otherwise a cached copy keeps referencing deleted old chunks.
|
||||
setHeaders: (res, filePath) => {
|
||||
if (filePath.includes(`${path.sep}assets${path.sep}`)) {
|
||||
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
||||
} else {
|
||||
res.setHeader("Cache-Control", "no-cache");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
app.setNotFoundHandler((request, reply) => {
|
||||
if (request.url.startsWith("/api/")) {
|
||||
return reply.status(404).send({ success: false, error: "Not found" });
|
||||
}
|
||||
// A missing hashed asset (old chunk after a deploy) must 404, NOT get
|
||||
// the SPA index.html fallback — HTML-as-JS masks the failure and breaks
|
||||
// the client's vite:preloadError reload recovery.
|
||||
if (request.url.startsWith("/assets/")) {
|
||||
return reply.status(404).send();
|
||||
}
|
||||
return reply.sendFile("index.html");
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user