import { lazy, Suspense, type ComponentType, type ReactNode } from 'react' type DynamicOptions = { loading?: () => ReactNode ssr?: boolean // Accepted-and-ignored: legacy/deprecated Next options. Listed so // call sites that pass them don't fail TypeScript. suspense?: boolean loadableGenerated?: unknown } type Loader

= () => Promise> | Promise<{ default: ComponentType

}> type DynamicComponent

= ComponentType

& { // Next stamps a `.preload()` on the returned component so consumers // can trigger the loader ahead of render (e.g. on hover). Returns a // promise that resolves when the loader settles. preload: () => Promise } function isDefaultExport

( value: ComponentType

| { default: ComponentType

} ): value is { default: ComponentType

} { return typeof value === 'object' && value !== null && 'default' in value } // eslint-disable-next-line no-restricted-exports export default function dynamic

( loader: Loader

, options: DynamicOptions = {} ): DynamicComponent

{ const { loading, ssr = true } = options // Cache the in-flight loader promise so calling `preload()` and then // rendering doesn't kick off a second import. Matches Next's behaviour // where preload is essentially a head-start on the same module load. let cached: Promise<{ default: ComponentType

}> | null = null const load = () => { if (cached) return cached cached = loader().then((mod) => (isDefaultExport

(mod) ? mod : { default: mod })) return cached } const Lazy = lazy(load) function DynamicComponent(props: P) { if (ssr === false && typeof window === 'undefined') return null return ( ) } ;(DynamicComponent as DynamicComponent

).preload = () => load().then(() => undefined) return DynamicComponent as DynamicComponent

}