From 33385b670d2a12110df840a6cd9369f07ddc674e Mon Sep 17 00:00:00 2001 From: Will Gordon Date: Thu, 30 Apr 2026 18:08:33 -0400 Subject: [PATCH 1/2] fix(app): auto-reload on stale chunk import failure Wraps lazy() imports with a catch handler that triggers window.location.reload() when a dynamic import fails due to a stale content hash after deployment. Uses sessionStorage with a 10s cooldown to prevent infinite reload loops. Fixes GITHUB-TRACKER-4 --- src/app/App.tsx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index d40269f2..efb00701 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -12,9 +12,25 @@ import OAuthCallback from "./pages/OAuthCallback"; import JiraCallback from "./pages/JiraCallback"; import PrivacyPage from "./pages/PrivacyPage"; -const DashboardPage = lazy(() => import("./components/dashboard/DashboardPage")); -const OnboardingWizard = lazy(() => import("./components/onboarding/OnboardingWizard")); -const SettingsPage = lazy(() => import("./components/settings/SettingsPage")); +const CHUNK_RELOAD_KEY = "github-tracker:chunk-reload"; +const CHUNK_RELOAD_MAX_AGE = 10_000; + +function lazyWithReload(loader: Parameters[0]) { + return lazy(() => + loader().catch((err) => { + const last = sessionStorage.getItem(CHUNK_RELOAD_KEY); + if (!last || Date.now() - Number(last) > CHUNK_RELOAD_MAX_AGE) { + sessionStorage.setItem(CHUNK_RELOAD_KEY, String(Date.now())); + window.location.reload(); + } + throw err; + }), + ); +} + +const DashboardPage = lazyWithReload(() => import("./components/dashboard/DashboardPage")); +const OnboardingWizard = lazyWithReload(() => import("./components/onboarding/OnboardingWizard")); +const SettingsPage = lazyWithReload(() => import("./components/settings/SettingsPage")); const SentryErrorBoundary = Sentry.withSentryErrorBoundary(ErrorBoundary); From e10263e929a4216bc126d40b81c51f1854993ed2 Mon Sep 17 00:00:00 2001 From: Will Gordon Date: Thu, 30 Apr 2026 18:18:49 -0400 Subject: [PATCH 2/2] fix(app): suppress Sentry noise during chunk reload Returns a never-resolving promise after triggering reload so the error does not propagate to the error boundary or Sentry. --- src/app/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/App.tsx b/src/app/App.tsx index efb00701..f6b98798 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -22,6 +22,7 @@ function lazyWithReload(loader: Parameters[0]) { if (!last || Date.now() - Number(last) > CHUNK_RELOAD_MAX_AGE) { sessionStorage.setItem(CHUNK_RELOAD_KEY, String(Date.now())); window.location.reload(); + return new Promise(() => {}); } throw err; }),