Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor next dynamic #44832

Merged
merged 5 commits into from Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -11,7 +11,7 @@ export function suspense() {

type Child = React.ReactElement<any, any>

export default function NoSSR({ children }: { children: Child }): Child {
export function NoSSR({ children }: { children: Child }): Child {
if (typeof window === 'undefined') {
suspense()
}
Expand Down
48 changes: 9 additions & 39 deletions packages/next/src/shared/lib/dynamic.tsx
@@ -1,17 +1,12 @@
import React, { lazy, Suspense } from 'react'
import React from 'react'
import Loadable from './loadable'
import NoSSR from './dynamic-no-ssr'

type ComponentModule<P = {}> = { default: React.ComponentType<P> }

export declare type LoaderComponent<P = {}> = Promise<
React.ComponentType<P> | ComponentModule<P>
>

type NormalizedLoader<P = {}> = () => Promise<{
default: React.ComponentType<P>
}>

export declare type Loader<P = {}> =
| (() => LoaderComponent<P>)
| LoaderComponent<P>
Expand Down Expand Up @@ -57,30 +52,6 @@ export type LoadableFn<P = {}> = (

export type LoadableComponent<P = {}> = React.ComponentType<P>

export function noSSR<P = {}>(
LoadableInitializer: NormalizedLoader<P>,
loadableOptions: DynamicOptions<P>
): React.ComponentType<P> {
// 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 = (
<Loading error={null} isLoading pastDelay={false} timedOut={false} />
)

return (props: any) => (
<Suspense fallback={fallback}>
<NoSSR>
<NoSSRComponent {...props} />
</NoSSR>
</Suspense>
)
}

export default function dynamic<P = {}>(
dynamicOptions: DynamicOptions<P> | Loader<P>,
options?: DynamicOptions<P>
Expand Down Expand Up @@ -127,26 +98,25 @@ export default function dynamic<P = {}>(
loadableOptions = { ...loadableOptions, ...options }

const loaderFn = loadableOptions.loader as () => LoaderComponent<P>
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<P> })
}
15 changes: 0 additions & 15 deletions packages/next/src/shared/lib/loadable.d.ts

This file was deleted.

Expand Up @@ -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[] = []
Expand Down Expand Up @@ -62,6 +63,7 @@ function createLoadableComponent(loadFn: any, options: any) {
timeout: null,
webpack: null,
modules: null,
ssr: true,
},
options
)
Expand Down Expand Up @@ -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 = (
<Loading isLoading={true} pastDelay={true} error={null} />
)

const Wrap = opts.ssr ? React.Fragment : NoSSR
const Lazy = opts.lazy

return React.createElement(
React.Suspense,
{
fallback: fallbackElement,
},
React.createElement(opts.lazy, props)
return (
<React.Suspense fallback={fallbackElement}>
<Wrap>
<Lazy {...props} />
</Wrap>
</React.Suspense>
)
}

Expand Down
4 changes: 4 additions & 0 deletions test/unit/next-dynamic.test.tsx
Expand Up @@ -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(<App />)
unmount()
Expand Down