fix(app): reload onto a new build instead of crashing on a missing chunk

A tab left open across a release asked for a lazy chunk the server no
longer has (prod: DownloadDialog 404 an hour after 0.89) and fell to the
crash screen. `vite:preloadError` now reloads the tab once a minute at
most; a second failure is let through to the error boundary, which now
wraps every entry — the public /watch, /privacy and /terms pages crashed
to a blank page.
This commit is contained in:
2026-09-19 04:51:31 +02:00
parent 3ee00fb051
commit 51e98bfc38
4 changed files with 148 additions and 40 deletions
@@ -2,6 +2,7 @@ import { Component, type ErrorInfo, type ReactNode } from "react";
import i18n from "../i18n";
import { notify } from "../lib/notifications";
import { errorAttrs, log } from "../lib/log";
import { reloadingForNewBuild } from "../lib/staleBuild";
interface Props {
children: ReactNode;
@@ -20,6 +21,9 @@ export default class ErrorBoundary extends Component<Props, State> {
}
componentDidCatch(error: Error, info: ErrorInfo) {
// The tab is already reloading onto a newer build (lib/staleBuild): this is the chunk it could not
// load, not a crash — no fatal notice, which would outlive the reload.
if (reloadingForNewBuild()) return;
log.fatal("ui.crash", "the app crashed while rendering", {
...errorAttrs(error),
...(info.componentStack ? { component_stack: info.componentStack } : {}),
@@ -34,6 +38,7 @@ export default class ErrorBoundary extends Component<Props, State> {
render() {
if (this.state.crashed) {
if (reloadingForNewBuild()) return null;
return (
<div className="min-h-screen grid place-items-center text-muted p-6 text-center">
<div>