feat(app): detect new deploy and prompt refresh (+ lazy-chunk recovery)
When a new version is deployed, open tabs no longer silently run stale code until a manual F5. - Server stamps every response with X-App-Version (src/middleware/version.ts, onSend hook in server.ts). - Client bakes its build version via Vite define (__APP_VERSION__); apiFetch compares the header to it (no polling — piggybacks existing traffic) and latches a mismatch in a small store (appVersion.ts). - UpdateBanner: a persistent bottom Snackbar "Je k dispozici nová verze aplikace. — Obnovit" → location.reload(). User-initiated, so an in-progress form is never interrupted. - lazyWithReload: every React.lazy page reloads once if its hashed chunk 404s after a deploy (sessionStorage-guarded against loops), fixing the "old chunk gone" error screen. Approach chosen after researching current SPA practice (version header + banner beats polling / a service worker for a non-PWA admin app). Tests: +4 (server header, client store latch/notify). Full suite 669 pass, tsc -b clean, lint 0. Verified live via Playwright (header emitted; banner appears on a simulated mismatch). Detection applies to deploys from the NEXT release onward (current clients lack the detection code). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import rateLimit from "@fastify/rate-limit";
|
||||
import path from "path";
|
||||
import { config } from "./config/env";
|
||||
import { securityHeaders } from "./middleware/security";
|
||||
import { registerVersionHeader } from "./middleware/version";
|
||||
import prisma from "./config/database";
|
||||
|
||||
import authRoutes from "./routes/admin/auth";
|
||||
@@ -100,6 +101,9 @@ async function start() {
|
||||
// --- Security headers ---
|
||||
app.addHook("onRequest", securityHeaders);
|
||||
|
||||
// --- Version header: lets the SPA detect a new deploy and prompt a refresh ---
|
||||
registerVersionHeader(app);
|
||||
|
||||
// --- Global error handler — consistent { success, error } format ---
|
||||
app.setErrorHandler(
|
||||
(err: Error & { statusCode?: number }, request, reply) => {
|
||||
|
||||
Reference in New Issue
Block a user