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

Fix next/dynamic types for resolving named export module #43923

Merged
merged 2 commits into from Dec 10, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -24,6 +24,7 @@ coverage
# test output
test/**/out*
test/**/next-env.d.ts
test/**/tsconfig.json
.DS_Store
/e2e-tests
test/tmp/**
Expand All @@ -46,4 +47,4 @@ test-timings.json

# Cache
*.tsbuildinfo
.swc/
.swc/
24 changes: 16 additions & 8 deletions packages/next/shared/lib/dynamic.tsx
Expand Up @@ -2,11 +2,19 @@ import React, { lazy, Suspense } from 'react'
import Loadable from './loadable'
import NoSSR from './dynamic-no-ssr'

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

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

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

export declare type Loader<P = {}> =
| (() => LoaderComponent<P>)
| LoaderComponent<P>

export type LoaderMap = { [module: string]: () => Loader<any> }

Expand All @@ -26,8 +34,8 @@ export type DynamicOptionsLoadingProps = {
// 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<T>(mod: ComponentModule<T>) {
return { default: mod.default || mod }
function convertModule<P>(mod: React.ComponentType<P> | ComponentModule<P>) {
return { default: (mod as ComponentModule<P>).default || mod }
}

export type DynamicOptions<P = {}> = LoadableGeneratedOptions & {
Expand All @@ -50,7 +58,7 @@ export type LoadableFn<P = {}> = (
export type LoadableComponent<P = {}> = React.ComponentType<P>

export function noSSR<P = {}>(
LoadableInitializer: Loader,
LoadableInitializer: NormalizedLoader<P>,
loadableOptions: DynamicOptions<P>
): React.ComponentType<P> {
// Removing webpack and modules means react-loadable won't try preloading
Expand Down Expand Up @@ -118,7 +126,7 @@ export default function dynamic<P = {}>(
// Support for passing options, eg: dynamic(import('../hello-world'), {loading: () => <p>Loading something</p>})
loadableOptions = { ...loadableOptions, ...options }

const loaderFn = loadableOptions.loader as Loader<P>
const loaderFn = loadableOptions.loader as () => LoaderComponent<P>
const loader = () => loaderFn().then(convertModule)

// coming from build/babel/plugins/react-loadable-plugin.js
Expand All @@ -135,7 +143,7 @@ export default function dynamic<P = {}>(
if (typeof loadableOptions.ssr === 'boolean') {
if (!loadableOptions.ssr) {
delete loadableOptions.ssr
return noSSR(loader as Loader, loadableOptions)
return noSSR(loader, loadableOptions)
}
delete loadableOptions.ssr
}
Expand Down
3 changes: 3 additions & 0 deletions test/production/typescript-basic/app/components/named.tsx
@@ -0,0 +1,3 @@
export function NamedExport() {
return <>named-export</>
}
10 changes: 10 additions & 0 deletions test/production/typescript-basic/app/pages/dynamic.tsx
@@ -0,0 +1,10 @@
import React from 'react'
import dynamic from 'next/dynamic'

const NamedExport = dynamic(() =>
import('../components/named').then((mod) => mod.NamedExport)
)

export default function Dynamic() {
return <NamedExport />
}