diff --git a/.gitignore b/.gitignore index 9a0d37330ba37..0474f7c1883a7 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 d3b639b68ef34..042438119d39a 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 = 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 (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
+ 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 0000000000000..4af8c9472dd33
--- /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 0000000000000..b008af163770a
--- /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