67 lines
1.9 KiB
TypeScript
67 lines
1.9 KiB
TypeScript
|
|
import {
|
||
|
|
Suspense,
|
||
|
|
lazy,
|
||
|
|
type ComponentType,
|
||
|
|
} from 'react';
|
||
|
|
import { LoadingSpinner } from '../loading-spinner';
|
||
|
|
import { logger } from '@/utils/logger';
|
||
|
|
import { LazyErrorFallback } from './LazyErrorFallback';
|
||
|
|
import { LazyErrorBoundary } from './LazyErrorBoundary';
|
||
|
|
|
||
|
|
function createLazyWithErrorHandling<T extends ComponentType<any>>(
|
||
|
|
importFunc: () => Promise<{ default: T } | T>,
|
||
|
|
pageName: string,
|
||
|
|
) {
|
||
|
|
return importFunc()
|
||
|
|
.then((module) => module as { default: T })
|
||
|
|
.catch((err) => {
|
||
|
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
||
|
|
logger.error('[LazyComponent] Failed to import lazy component', {
|
||
|
|
pageName,
|
||
|
|
error: errorMessage,
|
||
|
|
stack: err instanceof Error ? err.stack : undefined,
|
||
|
|
});
|
||
|
|
return Promise.resolve({
|
||
|
|
default: () => (
|
||
|
|
<LazyErrorFallback
|
||
|
|
pageName={pageName}
|
||
|
|
error={err instanceof Error ? err : new Error(errorMessage)}
|
||
|
|
/>
|
||
|
|
),
|
||
|
|
}) as unknown as Promise<{ default: T }>;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface LazyComponentProps {
|
||
|
|
fallback?: React.ReactNode;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function createLazyComponent<T extends ComponentType<any>>(
|
||
|
|
importFunc: () => Promise<any>,
|
||
|
|
fallback?: React.ReactNode,
|
||
|
|
pageName?: string,
|
||
|
|
) {
|
||
|
|
const safeImportFunc = pageName
|
||
|
|
? () => createLazyWithErrorHandling(importFunc as () => Promise<{ default: T }>, pageName)
|
||
|
|
: importFunc;
|
||
|
|
|
||
|
|
const LazyComponent = lazy(safeImportFunc);
|
||
|
|
|
||
|
|
return function WrappedLazyComponent(
|
||
|
|
props: React.ComponentProps<T> & LazyComponentProps,
|
||
|
|
) {
|
||
|
|
const { fallback: _fallback, ...componentProps } = props;
|
||
|
|
const component = (
|
||
|
|
<Suspense fallback={fallback ?? <LoadingSpinner />}>
|
||
|
|
<LazyComponent {...componentProps} />
|
||
|
|
</Suspense>
|
||
|
|
);
|
||
|
|
if (pageName) {
|
||
|
|
return (
|
||
|
|
<LazyErrorBoundary pageName={pageName}>{component}</LazyErrorBoundary>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return component;
|
||
|
|
};
|
||
|
|
}
|