feat(ux): auto-reload anti-tela-branca pós-deploy (stale chunk/bundle)

- watchdog inline no index.html: erro de asset /assets/ (404 de bundle antiga em
  cache), import dinâmico falho, ou #root vazio após 8s → reload automático
- index.tsx: listener vite:preloadError → reload
- anti-loop por timestamp (só recarrega se última tentativa >30s; re-arma sozinho)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-06-14 02:55:03 +02:00
parent df7678f70a
commit bbbe3705d8
2 changed files with 43 additions and 0 deletions
+32
View File
@@ -16,6 +16,38 @@
})();
</script>
<script>
/* Anti-tela-branca pós-deploy: se um asset (bundle/chunk/css) falhar — ex.: index
antigo em cache apontando p/ bundle removida (404) — ou o app não montar,
recarrega UMA vez para pegar o index/bundle novo. O flag é limpo no app ao
montar com sucesso, rearmando a proteção para o próximo deploy. */
(function () {
function reloadOnce() {
try {
var last = +sessionStorage.getItem('__sd_stale_reload__') || 0;
if (Date.now() - last < 30000) return; /* recarregou há <30s → evita loop */
sessionStorage.setItem('__sd_stale_reload__', String(Date.now()));
} catch (_) {}
location.reload();
}
window.addEventListener('error', function (e) {
var t = e && e.target; if (!t) return;
var url = t.src || t.href || '';
if ((t.tagName === 'SCRIPT' || t.tagName === 'LINK') && /\/assets\/|\/index\.tsx/.test(url)) reloadOnce();
}, true);
window.addEventListener('unhandledrejection', function (e) {
var m = e && e.reason && (e.reason.message || String(e.reason));
if (m && /dynamically imported module|module script failed|Failed to fetch/i.test(m)) reloadOnce();
});
window.addEventListener('load', function () {
setTimeout(function () {
var root = document.getElementById('root');
if (root && root.childElementCount === 0) reloadOnce();
}, 8000);
});
})();
</script>
<base href="/">
+11
View File
@@ -19,6 +19,17 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
// Auto-reload em chunk obsoleto pós-deploy (par do watchdog inline no index.html).
// Timestamp evita loop: só recarrega se a última tentativa foi há mais de 30s.
window.addEventListener('vite:preloadError', () => {
try {
const last = +(sessionStorage.getItem('__sd_stale_reload__') || 0);
if (Date.now() - last < 30000) return;
sessionStorage.setItem('__sd_stale_reload__', String(Date.now()));
} catch { /* ignore */ }
window.location.reload();
});
const rootElement = document.getElementById('root');
if (rootElement) {
const root = createRoot(rootElement);