5393b63cee
The first boot-slow capture (5763ms total, html 68ms) proved the white screen happens AFTER the shell arrives — but not which fetch eats the time. Append the 3 slowest resource entries (path, start→end, transferSize; sz0 ≈ served from SW/cache) so the next slow boot names its culprit. Reason cap 300→500 client+server to fit the detail. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
120 lines
6.4 KiB
HTML
120 lines
6.4 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
|
|
<link rel="apple-touch-icon" href="%sveltekit.assets%/icon-192.png" />
|
|
<link rel="manifest" href="%sveltekit.assets%/manifest.webmanifest" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta name="theme-color" content="#0083ad" />
|
|
<meta name="description" content="Calm, constructive news worth your attention — and nothing that isn't." />
|
|
<title>Upbeat Bytes — calm, constructive news</title>
|
|
<link rel="canonical" href="https://upbeatbytes.com/" />
|
|
<meta property="og:site_name" content="Upbeat Bytes" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:title" content="Upbeat Bytes — calm, constructive news" />
|
|
<meta property="og:description" content="Calm, constructive news worth your attention — and nothing that isn't. Summarized, so you get the gist and go deeper only if you want." />
|
|
<meta property="og:url" content="https://upbeatbytes.com/" />
|
|
<meta name="twitter:card" content="summary" />
|
|
<meta name="twitter:title" content="Upbeat Bytes — calm, constructive news" />
|
|
<meta name="twitter:description" content="Calm, constructive news, summarized — get the gist, go deeper only if you want." />
|
|
%sveltekit.head%
|
|
<style>
|
|
#boot-fallback {
|
|
display: none; position: fixed; inset: 0; z-index: 9999;
|
|
align-items: center; justify-content: center; background: #f7f4ec;
|
|
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; padding: 24px;
|
|
}
|
|
#boot-fallback .bf { text-align: center; max-width: 360px; }
|
|
#boot-fallback img { height: 46px; width: auto; margin-bottom: 18px; }
|
|
#boot-fallback p { color: #4a5560; font-size: 1rem; line-height: 1.55; margin: 0 0 20px; }
|
|
#boot-fallback button {
|
|
background: #0083ad; color: #fff; border: none; border-radius: 999px;
|
|
padding: 12px 26px; font: inherit; font-weight: 600; font-size: 0.95rem; cursor: pointer;
|
|
}
|
|
</style>
|
|
<script>
|
|
// Reliability seatbelt: never let a slow/failed boot become a silent white
|
|
// screen. Show a calm recovery card if the app hasn't mounted, and reload
|
|
// once on a chunk/preload failure (e.g. a just-deployed hashed chunk).
|
|
(function () {
|
|
var sent = false;
|
|
function report(reason) {
|
|
if (sent) return; sent = true; // one beacon per page
|
|
try {
|
|
var b = new Blob([JSON.stringify({ reason: String(reason || 'unknown').slice(0, 500),
|
|
path: location.pathname })], { type: 'application/json' });
|
|
navigator.sendBeacon && navigator.sendBeacon('/api/client-error', b);
|
|
} catch (e) { /* best-effort telemetry */ }
|
|
}
|
|
function showBoot(reason) {
|
|
if (window.__ubMounted) return; // app is running; in-app handles it
|
|
var el = document.getElementById('boot-fallback');
|
|
if (el) el.style.display = 'flex';
|
|
report(reason);
|
|
}
|
|
var timer = setTimeout(function () { showBoot('boot-timeout'); }, 10000);
|
|
// Svelte calls this once it has mounted (see +layout.svelte).
|
|
window.__ubBooted = function () {
|
|
window.__ubMounted = true;
|
|
clearTimeout(timer);
|
|
var el = document.getElementById('boot-fallback');
|
|
if (el && el.parentNode) el.parentNode.removeChild(el);
|
|
try { sessionStorage.removeItem('ub_reloaded'); } catch (e) {}
|
|
// Slow-but-successful boots (the "white screen, then it loaded" glitch)
|
|
// would otherwise leave no trace — beacon the timing so they're visible.
|
|
// performance.now() counts from navigation start, so a slow-arriving
|
|
// HTML document is included, not just slow JS.
|
|
try {
|
|
var ms = Math.round(performance.now());
|
|
if (ms > 4000) {
|
|
var nav = performance.getEntriesByType && performance.getEntriesByType('navigation')[0];
|
|
var detail = 'boot-slow: ' + ms + 'ms';
|
|
if (nav && nav.responseStart) detail += ' (html ' + Math.round(nav.responseStart) + 'ms)';
|
|
if (navigator.connection && navigator.connection.effectiveType)
|
|
detail += ' on ' + navigator.connection.effectiveType;
|
|
// Name the culprits: the 3 slowest resource fetches so far, with
|
|
// start→end so gaps (idle/SW churn) are distinguishable from slow
|
|
// downloads. size=0 usually means it came from the SW/cache.
|
|
var res = (performance.getEntriesByType('resource') || [])
|
|
.slice().sort(function (a, b) { return b.duration - a.duration; }).slice(0, 3)
|
|
.map(function (r) {
|
|
var name = r.name.replace(location.origin, '').slice(0, 80);
|
|
return name + ' ' + Math.round(r.startTime) + '→' + Math.round(r.responseEnd) + 'ms sz' + (r.transferSize || 0);
|
|
});
|
|
if (res.length) detail += ' | slowest: ' + res.join(' ; ');
|
|
report(detail);
|
|
}
|
|
} catch (e) { /* timing is best-effort */ }
|
|
};
|
|
addEventListener('vite:preloadError', function (e) {
|
|
report('preloadError: ' + ((e && e.payload && e.payload.message) || ''));
|
|
try {
|
|
if (!sessionStorage.getItem('ub_reloaded')) {
|
|
sessionStorage.setItem('ub_reloaded', '1');
|
|
e.preventDefault();
|
|
location.reload();
|
|
}
|
|
} catch (err) { /* ignore */ }
|
|
});
|
|
addEventListener('error', function (e) {
|
|
showBoot(e && (e.message || (e.error && e.error.message)) || 'error');
|
|
});
|
|
addEventListener('unhandledrejection', function (e) {
|
|
showBoot(e && e.reason && (e.reason.message || String(e.reason)) || 'rejection');
|
|
});
|
|
})();
|
|
</script>
|
|
</head>
|
|
<body data-sveltekit-preload-data="hover">
|
|
<div style="display: contents">%sveltekit.body%</div>
|
|
<div id="boot-fallback" role="alert" aria-live="polite">
|
|
<div class="bf">
|
|
<img src="%sveltekit.assets%/logo.svg" alt="Upbeat Bytes" />
|
|
<p>We had a little trouble loading. A quick refresh usually sorts it out.</p>
|
|
<button type="button" onclick="location.reload()">Refresh Upbeat Bytes</button>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|