Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 67 additions & 14 deletions src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,84 @@ export type AppRoute = Omit<PathRouteProps, 'path'> & {
showGlobalSearch?: boolean;
};

const CHUNK_RELOAD_SESSION_KEY = 'gt:chunk-reloaded';

/**
* Wraps `React.lazy` with a one-shot recovery for stale-deploy chunk hashes.
*
* Vite emits hashed chunk filenames (e.g. `WatchlistPage-<hash>.js`). After a
* deploy, the previous entry chunk references stale hashes that no longer
* exist on the server, causing `import()` to fail with "Failed to fetch
* dynamically imported module". Reloading `index.html` always fetches the
* current entry chunk with up-to-date references.
*
* A sessionStorage flag prevents an infinite reload loop if the chunk is
* genuinely missing (real 404, not a stale-hash 404).
*/
const lazyWithReload = <T extends React.ComponentType<any>>(
factory: () => Promise<{ default: T }>,
): React.LazyExoticComponent<T> =>
React.lazy(() =>
factory()
.then((mod) => {
// Successful chunk load — reset the recovery flag so any *future*
// stale-deploy event also gets one fresh reload attempt.
if (typeof window !== 'undefined') {
window.sessionStorage.removeItem(CHUNK_RELOAD_SESSION_KEY);
}
return mod;
})
.catch((err: Error) => {
const message = String(err?.message ?? err);
const isChunkLoadError =
/Failed to fetch dynamically imported module|Importing a module script failed|ChunkLoadError/i.test(
message,
);
if (
isChunkLoadError &&
typeof window !== 'undefined' &&
!window.sessionStorage.getItem(CHUNK_RELOAD_SESSION_KEY)
) {
window.sessionStorage.setItem(CHUNK_RELOAD_SESSION_KEY, '1');
window.location.reload();
// Resolve with an empty component while the reload is pending.
return { default: (() => null) as unknown as T };
}
throw err;
}),
);

// main menu pages
const HomePage = React.lazy(() => import('./pages/HomePage'));
const HomePage = lazyWithReload(() => import('./pages/HomePage'));
// AboutPage and FAQPage deleted — redirects inline below
const DashboardPage = React.lazy(
const DashboardPage = lazyWithReload(
() => import('./pages/dashboard/DashboardPage'),
);
const IssuesPage = React.lazy(() => import('./pages/IssuesPage'));
const SearchPage = React.lazy(() => import('./pages/search/SearchPage'));
const IssueDetailsPage = React.lazy(() => import('./pages/IssueDetailsPage'));
const TopMinersPage = React.lazy(() => import('./pages/TopMinersPage'));
const RepositoriesPage = React.lazy(() => import('./pages/RepositoriesPage'));
const MinerDetailsPage = React.lazy(() => import('./pages/MinerDetailsPage'));
const RepositoryDetailsPage = React.lazy(
const IssuesPage = lazyWithReload(() => import('./pages/IssuesPage'));
const SearchPage = lazyWithReload(() => import('./pages/search/SearchPage'));
const IssueDetailsPage = lazyWithReload(
() => import('./pages/IssueDetailsPage'),
);
const TopMinersPage = lazyWithReload(() => import('./pages/TopMinersPage'));
const RepositoriesPage = lazyWithReload(
() => import('./pages/RepositoriesPage'),
);
const MinerDetailsPage = lazyWithReload(
() => import('./pages/MinerDetailsPage'),
);
const RepositoryDetailsPage = lazyWithReload(
() => import('./pages/RepositoryDetailsPage'),
);
const PRDetailsPage = React.lazy(() => import('./pages/PRDetailsPage'));
const PRDetailsPage = lazyWithReload(() => import('./pages/PRDetailsPage'));

const OnboardPage = React.lazy(() => import('./pages/OnboardPage'));
const WatchlistPage = React.lazy(() => import('./pages/WatchlistPage'));
const RepositoryRegistrationPage = React.lazy(
const OnboardPage = lazyWithReload(() => import('./pages/OnboardPage'));
const WatchlistPage = lazyWithReload(() => import('./pages/WatchlistPage'));
const RepositoryRegistrationPage = lazyWithReload(
() => import('./pages/RepositoryRegistrationPage'),
);

// 404 page
const NotFoundPage = React.lazy(() => import('./pages/NotFoundPage'));
const NotFoundPage = lazyWithReload(() => import('./pages/NotFoundPage'));

const routesArray: AppRoute[] = [
{ name: 'home', path: '/', element: <HomePage /> },
Expand Down
Loading