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>
34 lines
1.3 KiB
TypeScript
34 lines
1.3 KiB
TypeScript
import React from "react";
|
|
import ReactDOM from "react-dom/client";
|
|
import { BrowserRouter } from "react-router-dom";
|
|
import App from "./App";
|
|
import { ThemeProvider } from "./context/ThemeContext";
|
|
|
|
// Deploy-skew recovery (official Vite mechanism): after a release the old
|
|
// hashed chunks are deleted, so a tab still running the previous build fails
|
|
// its next lazy-page import. Vite emits `vite:preloadError` for exactly this —
|
|
// swallow the error and reload once, which loads the fresh index.html and new
|
|
// chunk names. The timestamp guard prevents a reload loop when a chunk is
|
|
// genuinely unloadable (e.g. offline): a second failure within 10 s falls
|
|
// through to the normal error path.
|
|
window.addEventListener("vite:preloadError", (event) => {
|
|
const KEY = "vite-preload-reloaded-at";
|
|
const last = Number(sessionStorage.getItem(KEY) || 0);
|
|
if (Date.now() - last < 10_000) return;
|
|
sessionStorage.setItem(KEY, String(Date.now()));
|
|
event.preventDefault();
|
|
window.location.reload();
|
|
});
|
|
|
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
<React.StrictMode>
|
|
<BrowserRouter
|
|
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
|
|
>
|
|
<ThemeProvider>
|
|
<App />
|
|
</ThemeProvider>
|
|
</BrowserRouter>
|
|
</React.StrictMode>,
|
|
);
|