File size: 2,445 Bytes
fa9c65f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | interface EventTargetLike {
addEventListener: (type: string, listener: EventListenerOrEventListenerObject) => void;
}
interface StorageLike {
getItem: (key: string) => string | null;
setItem: (key: string, value: string) => void;
removeItem: (key: string) => void;
}
interface ChunkReloadGuardOptions {
eventTarget?: EventTargetLike;
storage?: StorageLike;
eventName?: string;
reload?: () => void;
}
const memorySessionStorage = new Map<string, string>();
function getSafeSessionStorage(): StorageLike {
let browserStorage: StorageLike | undefined;
try {
browserStorage = window.sessionStorage;
} catch {
// Storage access can throw in sandboxed frames or when cookies are blocked.
}
return {
getItem(key) {
try {
const stored = browserStorage?.getItem(key);
if (stored !== null && stored !== undefined) return stored;
} catch {
// Fall through to the in-memory one-shot guard.
}
return memorySessionStorage.get(key) ?? null;
},
setItem(key, value) {
try {
browserStorage?.setItem(key, value);
if (browserStorage) {
memorySessionStorage.delete(key);
return;
}
} catch {
// Preserve one-shot behavior for read-only or otherwise blocked storage.
}
memorySessionStorage.set(key, value);
},
removeItem(key) {
try {
browserStorage?.removeItem(key);
} catch {
// The in-memory guard still needs to be cleared below.
}
memorySessionStorage.delete(key);
},
};
}
export function buildChunkReloadStorageKey(version: string): string {
return `wm-chunk-reload:${version}`;
}
export function installChunkReloadGuard(
version: string,
options: ChunkReloadGuardOptions = {}
): string {
const storageKey = buildChunkReloadStorageKey(version);
const eventName = options.eventName ?? 'vite:preloadError';
const eventTarget = options.eventTarget ?? window;
const storage = options.storage ?? getSafeSessionStorage();
const reload = options.reload ?? (() => window.location.reload());
eventTarget.addEventListener(eventName, () => {
if (storage.getItem(storageKey)) return;
storage.setItem(storageKey, '1');
reload();
});
return storageKey;
}
export function clearChunkReloadGuard(storageKey: string, storage?: StorageLike): void {
(storage ?? getSafeSessionStorage()).removeItem(storageKey);
}
|