Skip to content

Commit

Permalink
add lazyWithRetry utility #174
Browse files Browse the repository at this point in the history
  • Loading branch information
ukorvl committed May 15, 2024
1 parent 1b54a61 commit adffcaa
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 5 deletions.
18 changes: 13 additions & 5 deletions src/features/routing/constants/routesConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@ import AuthContainer from '@/features/auth/components/AuthContainer/AuthContaine
import Layout from '@/features/shared/components/Layout/Layout';
import { Footer, Navbar } from '@/features/shared';
import { Path } from '../models/Paths';
import lazyWithRetry from '../utils/lazyWithRetry';

const MarketView = lazy(
const MarketView = lazyWithRetry(
() => import(/* webpackChunkName: "MarketView" */ '../../../views/MarketView'),
'MarketView',
);
const LoginView = lazy(
const LoginView = lazyWithRetry(
() => import(/* webpackChunkName: "LoginView" */ '../../../views/LoginView'),
'LoginView',
);
const PortfolioView = lazy(
const PortfolioView = lazyWithRetry(
() => import(/* webpackChunkName: "PortfolioView" */ '../../../views/PortfolioView'),
'PortfolioView',
);
const Page404 = lazy(() => import(/* webpackChunkName: "Page404" */ '../../../views/404'));
const RegisterView = lazy(
const Page404 = lazyWithRetry(
() => import(/* webpackChunkName: "Page404" */ '../../../views/404'),
'Page404',
);
const RegisterView = lazyWithRetry(
() => import(/* webpackChunkName: "RegisterView" */ '../../../views/RegisterView'),
'RegisterView',
);

/**
Expand Down
39 changes: 39 additions & 0 deletions src/features/routing/utils/lazyWithRetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @file Lazy load component with page reload on error.
* It helps to avoid the situation when the user is stuck on the page with a broken chunk.
*/

import { lazy } from 'react';
import { SessionStorageAPI } from '@/packages/sessionStorageAdapter';

type ComponentImportType = () => Promise<{ default: React.ComponentType }>;

const sessionKey = 'lazyWithRetry';

/**
* Lazy load component with page reload on error.
*
* @param componentImport - function that returns a promise with a component.
* @param name - name of the component.
* @returns - lazy loaded component.
*/
const lazyWithRetry = (componentImport: ComponentImportType, name: string) => {
return lazy(async () => {
const hasRefreshed = SessionStorageAPI.getItem(`${sessionKey}-${name}`) || 'false';

try {
SessionStorageAPI.setItem(`${sessionKey}-${name}`, 'false');
return await componentImport();
} catch (error) {
if (hasRefreshed === 'false') {
SessionStorageAPI.setItem(`${sessionKey}-${name}`, 'true');
window.location.reload();
}

if (hasRefreshed === 'true') throw new Error('chunkLoadError', error);
}
return await componentImport();
});
};

export default lazyWithRetry;
59 changes: 59 additions & 0 deletions src/packages/sessionStorageAdapter/SessionStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* @file Session storage API.
* @copyright Yury Korotovskikh <[email protected]>
*/

import type { SessionStorageKey } from './SessionStorageKey';

/**
* Session storage API.
*/
class SessionStorage {
/**
* Get sesstionStorage item.
*
* @param ItemKey - Key.
* @returns Item value.
*/
public getItem<T>(ItemKey: SessionStorageKey): T | undefined {
try {
const serialisedValue = sessionStorage.getItem(ItemKey);
if (serialisedValue === null) {
return undefined;
}
return JSON.parse(serialisedValue);
} catch {
return undefined;
}
}

/**
* Set sessionStorage item.
*
* @param ItemKey - Key.
* @param ItemValue - Value.
*/
public setItem<T>(ItemKey: SessionStorageKey, ItemValue: T): void {
try {
const serialisedValue = JSON.stringify(ItemValue);
sessionStorage.setItem(ItemKey, serialisedValue);
} catch {
// Do nothing
}
}

/**
* Remove item from sessionStorage.
*
* @param ItemKey - Key.
*/
public removeItem(ItemKey: SessionStorageKey): void {
try {
sessionStorage.removeItem(ItemKey);
} catch {
// Do nothing
}
}
}

export const SessionStorageAPI = new SessionStorage();
9 changes: 9 additions & 0 deletions src/packages/sessionStorageAdapter/SessionStorageKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @file Type declaration.
* @copyright Yury Korotovskikh <[email protected]>
*/

/**
* Session storage avialiable keys.
*/
export type SessionStorageKey = `lazyWithRetry-${string}`;
7 changes: 7 additions & 0 deletions src/packages/sessionStorageAdapter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @file Index.
* @copyright Yury Korotovskikh <[email protected]>
*/

export { SessionStorageAPI } from './SessionStorage';
export type { SessionStorageKey } from './SessionStorageKey';

0 comments on commit adffcaa

Please sign in to comment.