|
1 |
| -import { Suspense, lazy, Fragment } from 'react' |
2 |
| -import { NoSSR } from './dynamic-no-ssr' |
| 1 | +import { Suspense, lazy } from 'react' |
| 2 | +import { BailoutToCSR } from './dynamic-bailout-to-csr' |
3 | 3 | import type { ComponentModule } from './types'
|
4 | 4 |
|
5 | 5 | // Normalize loader to return the module as form { default: Component } for `React.lazy`.
|
6 | 6 | // Also for backward compatible since next/dynamic allows to resolve a component directly with loader
|
7 | 7 | // Client component reference proxy need to be converted to a module.
|
8 | 8 | function convertModule<P>(mod: React.ComponentType<P> | ComponentModule<P>) {
|
9 |
| - return { default: (mod as ComponentModule<P>)?.default || mod } |
| 9 | + return { default: (mod as ComponentModule<P>)?.default ?? mod } |
10 | 10 | }
|
11 | 11 |
|
12 |
| -function Loadable(options: any) { |
13 |
| - const opts = { |
14 |
| - loader: null, |
15 |
| - loading: null, |
16 |
| - ssr: true, |
17 |
| - ...options, |
18 |
| - } |
| 12 | +const defaultOptions = { |
| 13 | + loader: () => Promise.resolve(convertModule(() => null)), |
| 14 | + loading: null, |
| 15 | + ssr: true, |
| 16 | +} |
19 | 17 |
|
20 |
| - const loader = () => |
21 |
| - opts.loader != null |
22 |
| - ? opts.loader().then(convertModule) |
23 |
| - : Promise.resolve(convertModule(() => null)) |
| 18 | +interface LoadableOptions { |
| 19 | + loader?: () => Promise<React.ComponentType<any> | ComponentModule<any>> |
| 20 | + loading?: React.ComponentType<any> | null |
| 21 | + ssr?: boolean |
| 22 | +} |
24 | 23 |
|
25 |
| - const Lazy = lazy(loader) |
| 24 | +function Loadable(options: LoadableOptions) { |
| 25 | + const opts = { ...defaultOptions, ...options } |
| 26 | + const Lazy = lazy(() => opts.loader().then(convertModule)) |
26 | 27 | const Loading = opts.loading
|
27 |
| - const Wrap = opts.ssr ? Fragment : NoSSR |
28 | 28 |
|
29 | 29 | function LoadableComponent(props: any) {
|
30 | 30 | const fallbackElement = Loading ? (
|
31 | 31 | <Loading isLoading={true} pastDelay={true} error={null} />
|
32 | 32 | ) : null
|
33 | 33 |
|
34 |
| - return ( |
35 |
| - <Suspense fallback={fallbackElement}> |
36 |
| - <Wrap> |
37 |
| - <Lazy {...props} /> |
38 |
| - </Wrap> |
39 |
| - </Suspense> |
| 34 | + const children = opts.ssr ? ( |
| 35 | + <Lazy {...props} /> |
| 36 | + ) : ( |
| 37 | + <BailoutToCSR reason="next/dynamic"> |
| 38 | + <Lazy {...props} /> |
| 39 | + </BailoutToCSR> |
40 | 40 | )
|
| 41 | + |
| 42 | + return <Suspense fallback={fallbackElement}>{children}</Suspense> |
41 | 43 | }
|
42 | 44 |
|
43 | 45 | LoadableComponent.displayName = 'LoadableComponent'
|
|
0 commit comments