/**
* Страховка от белого экрана на протухшем index.html (Q-0365).
*
* Прод-nginx отдаёт HTML с `max-age=300, stale-while-revalidate=3600`, поэтому
* после деплоя браузер ещё какое-то время держит старую разметку со старыми
* хешами бандлов. Основное лечение — серверное: деплой больше не сносит ассеты
* предыдущих СЃР±РѕСЂРѕРє (архив РІ deploy.yml + `location @assets_archive`). Ртот
* файл — вторая линия: ассет мог выпасть из окна архива, а страница всё равно
* не должна оставаться белой.
*
* Почему не в main.tsx: обработчик `vite:preloadError` там ловит только сбой
* ЛЕНРВОГО чанка, то есть РєРѕРіРґР° приложение СѓР¶Рµ стартовало. Если 404 отдаёт сам
* входной бандл (`<script type="module" src="/assets/index-*.js">`), не
* выполняется ни одной строки бандла — ловить событие некому. Поэтому обработчик
* живёт отдельным классическим скриптом в <head> ДО модульного: классические
* скрипты выполняются при разборе, модульные — отложенно.
*
* Почему отдельный файл, а не inline: CSP `script-src 'self'` без
* 'unsafe-inline' (deploy/nginx-security-headers.inc) — inline-скрипт был бы
* заблокирован. Тем же способом подключён /theme-init.js.
*
* Почему fetch перед reload: обычный `location.reload()` возьмёт тот же самый
* протухший HTML из HTTP-кеша, и мы получим ту же белую страницу. Запрос с
* `cache: "reload"` идёт мимо кеша и обновляет запись, после чего перезагрузка
* получает свежую разметку.
*
* Защита от петли — таймстамп в sessionStorage, как у обработчика
* `vite:preloadError` в main.tsx (там окно 10 секунд). Окно намеренно НЕ
* сбрасывается при успешном старте приложения: иначе два обработчика на одном
* и том же не загрузившемся чанке гоняли бы страницу по кругу — старт чистит
* счётчик, следующий сбой перезагружает, и так до истечения TTL кеша.
* Сломанный по-настоящему деплой (ассета нет ни в сборке, ни в архиве) даёт
* максимум одну перезагрузку в минуту, а не подряд.
*/
(function () {
"use strict";
var FLAG = "avalog:stale-html-reload-at";
var COOLDOWN_MS = 60000;
window.addEventListener(
"error",
function (event) {
var el = event && event.target;
// Нас интересует ТОЛЬКО ошибка загрузки ресурса: у неё target —
// элемент, а не window (у обычной JS-ошибки target === window).
if (!el || el === window || !el.tagName) return;
var tag = String(el.tagName).toLowerCase();
if (tag !== "script" && tag !== "link") return;
// Свои бандлы лежат в /assets/ с хешем в имени. Падение стороннего
// скрипта (аналитика, чат) перезагрузкой не лечится.
var url = el.src || el.href || "";
if (url.indexOf("/assets/") === -1) return;
try {
var last = Number(sessionStorage.getItem(FLAG) || 0);
if (Date.now() - last < COOLDOWN_MS) return;
sessionStorage.setItem(FLAG, String(Date.now()));
} catch (e) {
// Приватный режим / отключённое хранилище — без защиты от петли
// перезагружаться нельзя.
return;
}
var reload = function () {
window.location.reload();
};
if (typeof window.fetch === "function") {
window
.fetch(window.location.href, { cache: "reload", credentials: "same-origin" })
.then(reload, reload);
} else {
reload();
}
},
true // capture: ошибки загрузки ресурсов не всплывают
);
})();