Handle stale frontend assets and harden worker startup
这个提交包含在:
@@ -9,6 +9,7 @@ import { getLoginUrl } from "./const";
|
||||
import "./index.css";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
const ASSET_REFRESH_KEY = "asset-recovery-reloaded";
|
||||
|
||||
const redirectToLoginIfUnauthorized = (error: unknown) => {
|
||||
if (!(error instanceof TRPCClientError)) return;
|
||||
@@ -21,6 +22,60 @@ const redirectToLoginIfUnauthorized = (error: unknown) => {
|
||||
window.location.href = getLoginUrl();
|
||||
};
|
||||
|
||||
function reloadForStaleAsset(reason: string) {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const alreadyReloaded = window.sessionStorage.getItem(ASSET_REFRESH_KEY) === "1";
|
||||
if (alreadyReloaded) {
|
||||
console.error("[Asset Recovery] stale asset still failing after reload", reason);
|
||||
return;
|
||||
}
|
||||
|
||||
window.sessionStorage.setItem(ASSET_REFRESH_KEY, "1");
|
||||
console.warn("[Asset Recovery] reloading page due to stale asset failure:", reason);
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function clearAssetRecoveryFlag() {
|
||||
if (typeof window === "undefined") return;
|
||||
window.sessionStorage.removeItem(ASSET_REFRESH_KEY);
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("load", () => {
|
||||
clearAssetRecoveryFlag();
|
||||
}, { once: true });
|
||||
|
||||
window.addEventListener("vite:preloadError", (event) => {
|
||||
const customEvent = event as Event & { payload?: unknown; preventDefault: () => void };
|
||||
customEvent.preventDefault();
|
||||
reloadForStaleAsset(String(customEvent.payload ?? "vite preload error"));
|
||||
});
|
||||
|
||||
window.addEventListener("error", (event) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLLinkElement || target instanceof HTMLScriptElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const assetUrl = target instanceof HTMLLinkElement ? target.href : target.src;
|
||||
if (assetUrl.includes("/assets/")) {
|
||||
reloadForStaleAsset(assetUrl);
|
||||
}
|
||||
}, true);
|
||||
|
||||
window.addEventListener("unhandledrejection", (event) => {
|
||||
const reason = event.reason instanceof Error ? event.reason.message : String(event.reason ?? "");
|
||||
if (
|
||||
reason.includes("Failed to fetch dynamically imported module") ||
|
||||
reason.includes("Importing a module script failed") ||
|
||||
reason.includes("Unable to preload CSS")
|
||||
) {
|
||||
reloadForStaleAsset(reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
queryClient.getQueryCache().subscribe(event => {
|
||||
if (event.type === "updated" && event.action.type === "error") {
|
||||
const error = event.query.state.error;
|
||||
|
||||
在新工单中引用
屏蔽一个用户