diff --git a/packages/next/src/shared/lib/app-dynamic.tsx b/packages/next/src/shared/lib/app-dynamic.tsx index 6884ad9d35c36..9efbc8aed56b6 100644 --- a/packages/next/src/shared/lib/app-dynamic.tsx +++ b/packages/next/src/shared/lib/app-dynamic.tsx @@ -1,34 +1,18 @@ import React from 'react' import Loadable from './lazy-dynamic/loadable' -type ComponentModule

= { default: React.ComponentType

} - -export declare type LoaderComponent

= Promise< - React.ComponentType

| ComponentModule

-> - -export declare type Loader

= () => LoaderComponent

- -export type LoaderMap = { [module: string]: () => Loader } - -export type LoadableGeneratedOptions = { - webpack?(): any - modules?(): LoaderMap -} - -export type DynamicOptionsLoadingProps = { - error?: Error | null - isLoading?: boolean - pastDelay?: boolean - retry?: () => void - timedOut?: boolean -} - -// Normalize loader to return the module as form { default: Component } for `React.lazy`. -// Also for backward compatible since next/dynamic allows to resolve a component directly with loader -// Client component reference proxy need to be converted to a module. -function convertModule

(mod: React.ComponentType

| ComponentModule

) { - return { default: (mod as ComponentModule

)?.default || mod } +import type { + LoadableGeneratedOptions, + DynamicOptionsLoadingProps, + Loader, + LoaderComponent, +} from './lazy-dynamic/types' + +export { + type LoadableGeneratedOptions, + type DynamicOptionsLoadingProps, + type Loader, + type LoaderComponent, } export type DynamicOptions

= LoadableGeneratedOptions & { @@ -50,8 +34,6 @@ export default function dynamic

( dynamicOptions: DynamicOptions

| Loader

, options?: DynamicOptions

): React.ComponentType

{ - const loadableFn: LoadableFn

= Loadable - const loadableOptions: LoadableOptions

= { // A loading component is not required, so we default it loading: ({ error, isLoading, pastDelay }) => { @@ -78,13 +60,5 @@ export default function dynamic

( loadableOptions.loader = dynamicOptions } - Object.assign(loadableOptions, options) - - const loaderFn = loadableOptions.loader as () => LoaderComponent

- const loader = () => - loaderFn != null - ? loaderFn().then(convertModule) - : Promise.resolve(convertModule(() => null)) - - return loadableFn({ ...loadableOptions, loader: loader as Loader

}) + return Loadable({ ...loadableOptions, ...options }) } diff --git a/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx b/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx index 69b41545e6a96..d5dc700d8ee53 100644 --- a/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx +++ b/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx @@ -1,33 +1,42 @@ -import React from 'react' +import { Suspense, lazy, Fragment } from 'react' import { NoSSR } from './dynamic-no-ssr' +import type { ComponentModule } from './types' + +// Normalize loader to return the module as form { default: Component } for `React.lazy`. +// Also for backward compatible since next/dynamic allows to resolve a component directly with loader +// Client component reference proxy need to be converted to a module. +function convertModule

(mod: React.ComponentType

| ComponentModule

) { + return { default: (mod as ComponentModule

)?.default || mod } +} function Loadable(options: any) { - const opts = Object.assign( - { - loader: null, - loading: null, - ssr: true, - }, - options - ) + const opts = { + loader: null, + loading: null, + ssr: true, + ...options, + } - opts.lazy = React.lazy(opts.loader) + const loader = () => + opts.loader != null + ? opts.loader().then(convertModule) + : Promise.resolve(convertModule(() => null)) + + const Lazy = lazy(loader) + const Loading = opts.loading + const Wrap = opts.ssr ? Fragment : NoSSR function LoadableComponent(props: any) { - const Loading = opts.loading - const fallbackElement = ( + const fallbackElement = Loading ? ( - ) - - const Wrap = opts.ssr ? React.Fragment : NoSSR - const Lazy = opts.lazy + ) : null return ( - + - + ) } diff --git a/packages/next/src/shared/lib/lazy-dynamic/types.ts b/packages/next/src/shared/lib/lazy-dynamic/types.ts new file mode 100644 index 0000000000000..64b8209cbfd2b --- /dev/null +++ b/packages/next/src/shared/lib/lazy-dynamic/types.ts @@ -0,0 +1,22 @@ +export type ComponentModule

= { default: React.ComponentType

} + +export declare type LoaderComponent

= Promise< + React.ComponentType

| ComponentModule

+> + +export declare type Loader

= () => LoaderComponent

+ +export type LoaderMap = { [module: string]: () => Loader } + +export type LoadableGeneratedOptions = { + webpack?(): any + modules?(): LoaderMap +} + +export type DynamicOptionsLoadingProps = { + error?: Error | null + isLoading?: boolean + pastDelay?: boolean + retry?: () => void + timedOut?: boolean +}