diff --git a/packages/next/src/shared/lib/dynamic-no-ssr.ts b/packages/next/src/shared/lib/dynamic-no-ssr.tsx similarity index 83% rename from packages/next/src/shared/lib/dynamic-no-ssr.ts rename to packages/next/src/shared/lib/dynamic-no-ssr.tsx index d32e49b51639..e5c1c1e22b2c 100644 --- a/packages/next/src/shared/lib/dynamic-no-ssr.ts +++ b/packages/next/src/shared/lib/dynamic-no-ssr.tsx @@ -11,7 +11,7 @@ export function suspense() { type Child = React.ReactElement -export default function NoSSR({ children }: { children: Child }): Child { +export function NoSSR({ children }: { children: Child }): Child { if (typeof window === 'undefined') { suspense() } diff --git a/packages/next/src/shared/lib/dynamic.tsx b/packages/next/src/shared/lib/dynamic.tsx index 042438119d39..cd12962f493c 100644 --- a/packages/next/src/shared/lib/dynamic.tsx +++ b/packages/next/src/shared/lib/dynamic.tsx @@ -1,6 +1,5 @@ -import React, { lazy, Suspense } from 'react' +import React from 'react' import Loadable from './loadable' -import NoSSR from './dynamic-no-ssr' type ComponentModule

= { default: React.ComponentType

} @@ -8,10 +7,6 @@ export declare type LoaderComponent

= Promise< React.ComponentType

| ComponentModule

> -type NormalizedLoader

= () => Promise<{ - default: React.ComponentType

-}> - export declare type Loader

= | (() => LoaderComponent

) | LoaderComponent

@@ -57,30 +52,6 @@ export type LoadableFn

= ( export type LoadableComponent

= React.ComponentType

-export function noSSR

( - LoadableInitializer: NormalizedLoader

, - loadableOptions: DynamicOptions

-): React.ComponentType

{ - // Removing webpack and modules means react-loadable won't try preloading - delete loadableOptions.webpack - delete loadableOptions.modules - - const NoSSRComponent = lazy(LoadableInitializer) - - const Loading = loadableOptions.loading! - const fallback = ( - - ) - - return (props: any) => ( - - - - - - ) -} - export default function dynamic

( dynamicOptions: DynamicOptions

| Loader

, options?: DynamicOptions

@@ -127,26 +98,25 @@ export default function dynamic

( loadableOptions = { ...loadableOptions, ...options } const loaderFn = loadableOptions.loader as () => LoaderComponent

- const loader = () => loaderFn().then(convertModule) + const loader = () => + loaderFn != null + ? loaderFn().then(convertModule) + : Promise.resolve(convertModule(() => null)) // coming from build/babel/plugins/react-loadable-plugin.js if (loadableOptions.loadableGenerated) { loadableOptions = { ...loadableOptions, ...loadableOptions.loadableGenerated, - loader, } delete loadableOptions.loadableGenerated } // support for disabling server side rendering, eg: dynamic(() => import('../hello-world'), {ssr: false}). - if (typeof loadableOptions.ssr === 'boolean') { - if (!loadableOptions.ssr) { - delete loadableOptions.ssr - return noSSR(loader, loadableOptions) - } - delete loadableOptions.ssr + if (typeof loadableOptions.ssr === 'boolean' && !loadableOptions.ssr) { + delete loadableOptions.webpack + delete loadableOptions.modules } - return loadableFn(loadableOptions) + return loadableFn({ ...loadableOptions, loader: loader as Loader

}) } diff --git a/packages/next/src/shared/lib/loadable.d.ts b/packages/next/src/shared/lib/loadable.d.ts deleted file mode 100644 index 8ac6e8043379..000000000000 --- a/packages/next/src/shared/lib/loadable.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* tslint:disable */ -import React from 'react' - -declare namespace LoadableExport { - interface ILoadable { -

(opts: any): React.ComponentClass

- Map

(opts: any): React.ComponentType

- preloadAll(): Promise - } -} - -// eslint-disable-next-line @typescript-eslint/no-redeclare -declare const LoadableExport: LoadableExport.ILoadable - -export = LoadableExport diff --git a/packages/next/src/shared/lib/loadable.ts b/packages/next/src/shared/lib/loadable.tsx similarity index 94% rename from packages/next/src/shared/lib/loadable.ts rename to packages/next/src/shared/lib/loadable.tsx index 3d075c1957f3..d4758716cc17 100644 --- a/packages/next/src/shared/lib/loadable.ts +++ b/packages/next/src/shared/lib/loadable.tsx @@ -23,6 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE // Modified to be compatible with webpack 4 / Next.js import React from 'react' +import { NoSSR } from './dynamic-no-ssr' import { LoadableContext } from './loadable-context' const ALL_INITIALIZERS: any[] = [] @@ -62,6 +63,7 @@ function createLoadableComponent(loadFn: any, options: any) { timeout: null, webpack: null, modules: null, + ssr: true, }, options ) @@ -117,21 +119,24 @@ function createLoadableComponent(loadFn: any, options: any) { }) } } + function LoadableComponent(props: any) { useLoadableModule() - const fallbackElement = React.createElement(opts.loading, { - isLoading: true, - pastDelay: true, - error: null, - }) + const Loading = opts.loading + const fallbackElement = ( + + ) + + const Wrap = opts.ssr ? React.Fragment : NoSSR + const Lazy = opts.lazy - return React.createElement( - React.Suspense, - { - fallback: fallbackElement, - }, - React.createElement(opts.lazy, props) + return ( + + + + + ) } diff --git a/test/unit/next-dynamic.test.tsx b/test/unit/next-dynamic.test.tsx index e78e15d6ff0e..2e1c7cdea09d 100644 --- a/test/unit/next-dynamic.test.tsx +++ b/test/unit/next-dynamic.test.tsx @@ -8,6 +8,10 @@ import dynamic from 'next/dynamic' describe('next/dynamic', () => { it('test dynamic with jest', () => { const App = dynamic(() => import('./fixtures/stub-components/hello')) + + // @ts-ignore + expect(App.preload).toBeDefined() + act(() => { const { unmount } = render() unmount()