From 3833aed08dd890231f78970d001416f5c1da17f2 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 10 Dec 2022 18:35:13 +0100 Subject: [PATCH] Fix next/dynamic types for resolving named export module (#43923) ## Bug Fixes: #43915 - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) --- .gitignore | 3 ++- packages/next/shared/lib/dynamic.tsx | 24 ++++++++++++------- .../typescript-basic/app/components/named.tsx | 3 +++ .../typescript-basic/app/pages/dynamic.tsx | 10 ++++++++ 4 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 test/production/typescript-basic/app/components/named.tsx create mode 100644 test/production/typescript-basic/app/pages/dynamic.tsx diff --git a/.gitignore b/.gitignore index 9a0d37330ba3792..0474f7c1883a746 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ coverage # test output test/**/out* test/**/next-env.d.ts +test/**/tsconfig.json .DS_Store /e2e-tests test/tmp/** @@ -46,4 +47,4 @@ test-timings.json # Cache *.tsbuildinfo -.swc/ \ No newline at end of file +.swc/ diff --git a/packages/next/shared/lib/dynamic.tsx b/packages/next/shared/lib/dynamic.tsx index d3b639b68ef34d8..042438119d39a5b 100644 --- a/packages/next/shared/lib/dynamic.tsx +++ b/packages/next/shared/lib/dynamic.tsx @@ -2,11 +2,19 @@ import React, { lazy, Suspense } from 'react' import Loadable from './loadable' import NoSSR from './dynamic-no-ssr' -type ComponentModule

= { default: React.ComponentType

} +type ComponentModule

= { default: React.ComponentType

} -export type LoaderComponent

= Promise> +export declare type LoaderComponent

= Promise< + React.ComponentType

| ComponentModule

+> -export type Loader

= () => LoaderComponent

+type NormalizedLoader

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

+}> + +export declare type Loader

= + | (() => LoaderComponent

) + | LoaderComponent

export type LoaderMap = { [module: string]: () => Loader } @@ -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(mod: ComponentModule) { - return { default: mod.default || mod } +function convertModule

(mod: React.ComponentType

| ComponentModule

) { + return { default: (mod as ComponentModule

).default || mod } } export type DynamicOptions

= LoadableGeneratedOptions & { @@ -50,7 +58,7 @@ export type LoadableFn

= ( export type LoadableComponent

= React.ComponentType

export function noSSR

( - LoadableInitializer: Loader, + LoadableInitializer: NormalizedLoader

, loadableOptions: DynamicOptions

): React.ComponentType

{ // Removing webpack and modules means react-loadable won't try preloading @@ -118,7 +126,7 @@ export default function dynamic

( // Support for passing options, eg: dynamic(import('../hello-world'), {loading: () =>

Loading something

}) loadableOptions = { ...loadableOptions, ...options } - const loaderFn = loadableOptions.loader as Loader

+ const loaderFn = loadableOptions.loader as () => LoaderComponent

const loader = () => loaderFn().then(convertModule) // coming from build/babel/plugins/react-loadable-plugin.js @@ -135,7 +143,7 @@ export default function dynamic

( if (typeof loadableOptions.ssr === 'boolean') { if (!loadableOptions.ssr) { delete loadableOptions.ssr - return noSSR(loader as Loader, loadableOptions) + return noSSR(loader, loadableOptions) } delete loadableOptions.ssr } diff --git a/test/production/typescript-basic/app/components/named.tsx b/test/production/typescript-basic/app/components/named.tsx new file mode 100644 index 000000000000000..4af8c9472dd33ab --- /dev/null +++ b/test/production/typescript-basic/app/components/named.tsx @@ -0,0 +1,3 @@ +export function NamedExport() { + return <>named-export +} diff --git a/test/production/typescript-basic/app/pages/dynamic.tsx b/test/production/typescript-basic/app/pages/dynamic.tsx new file mode 100644 index 000000000000000..b008af163770ad7 --- /dev/null +++ b/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 +}