diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 33c870e10935fa..fc1105a5a79f18 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -483,13 +483,6 @@ export default async function getBaseWebpackConfig( babel: useSWCLoader ? swcDefaultLoader : babelLoader!, } - const nextFlightLoader = { - loader: 'next-flight-loader', - options: { - isEdgeServer, - }, - } - const appServerLayerLoaders = hasAppDir ? [ // When using Babel, we will have to add the SWC loader @@ -502,7 +495,6 @@ export default async function getBaseWebpackConfig( : [] const instrumentLayerLoaders = [ - nextFlightLoader, // When using Babel, we will have to add the SWC loader // as an additional pass to handle RSC correctly. // This will cause some performance overhead but @@ -512,7 +504,6 @@ export default async function getBaseWebpackConfig( ].filter(Boolean) const middlewareLayerLoaders = [ - nextFlightLoader, // When using Babel, we will have to use SWC to do the optimization // for middleware to tree shake the unused default optimized imports like "next/server". // This will cause some performance overhead but @@ -1358,7 +1349,9 @@ export default async function getBaseWebpackConfig( isEdgeServer, }), }, - use: nextFlightLoader, + use: { + loader: 'next-flight-loader', + }, }, ] : []), diff --git a/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts b/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts index 445df1d1de8c94..79a0ae48ef6ea0 100644 --- a/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts +++ b/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts @@ -54,9 +54,6 @@ export default function transformSource( throw new Error('Expected source to have been transformed to a string.') } - const options = this.getOptions() - const { isEdgeServer } = options - // Assign the RSC meta information to buildInfo. // Exclude next internal files which are not marked as client files const buildInfo = getModuleBuildInfo(this._module) @@ -100,31 +97,21 @@ export default function transformSource( return } - // `proxy` is the module proxy that we treat the module as a client boundary. - // For ESM, we access the property of the module proxy directly for each export. - // This is bit hacky that treating using a CJS like module proxy for ESM's exports, - // but this will avoid creating nested proxies for each export. It will be improved in the future. - - // Explanation for: await createProxy(...) - // We need to await the module proxy creation because it can be async module for SSR layer - // due to having async dependencies. - // We only apply `the await` for Node.js as only Edge doesn't have external dependencies. let esmSource = `\ import { createProxy } from "${MODULE_PROXY_PATH}" - -const proxy = ${ - isEdgeServer ? '' : 'await' - } createProxy(String.raw\`${resourceKey}\`) ` let cnt = 0 for (const ref of clientRefs) { if (ref === '') { - esmSource += `exports[''] = proxy['']\n` + esmSource += `\nexports[''] = createProxy(String.raw\`${resourceKey}#\`);` } else if (ref === 'default') { - esmSource += `export default proxy.default;\n` + esmSource += `\ +export default createProxy(String.raw\`${resourceKey}#default\`); +` } else { - esmSource += `const e${cnt} = proxy["${ref}"];\n` - esmSource += `export { e${cnt++} as ${ref} };\n` + esmSource += ` +const e${cnt} = createProxy(String.raw\`${resourceKey}#${ref}\`); +export { e${cnt++} as ${ref} };` } } diff --git a/packages/next/src/server/app-render/create-component-tree.tsx b/packages/next/src/server/app-render/create-component-tree.tsx index 1f348d230be151..a23149fa78d57d 100644 --- a/packages/next/src/server/app-render/create-component-tree.tsx +++ b/packages/next/src/server/app-render/create-component-tree.tsx @@ -260,7 +260,7 @@ async function createComponentTreeInternal({ } const LayoutOrPage: React.ComponentType | undefined = layoutOrPageMod - ? interopDefault(layoutOrPageMod) + ? await interopDefault(layoutOrPageMod) : undefined /** diff --git a/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx b/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx index 8ecbf703c6d5eb..1aa448a61e366a 100644 --- a/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx +++ b/packages/next/src/shared/lib/lazy-dynamic/loadable.tsx @@ -15,7 +15,7 @@ function convertModule

( // Cases: // mod: { default: Component } // mod: Component - // mod: { default: proxy(Component) } + // mod: { $$typeof, default: proxy(Component) } // mod: proxy(Component) const hasDefault = mod && 'default' in mod return { diff --git a/test/e2e/app-dir/app-routes-client-component/app-routes-client-component.test.ts b/test/e2e/app-dir/app-routes-client-component/app-routes-client-component.test.ts index b0a5079ac0a642..774b3a9daf1b69 100644 --- a/test/e2e/app-dir/app-routes-client-component/app-routes-client-component.test.ts +++ b/test/e2e/app-dir/app-routes-client-component/app-routes-client-component.test.ts @@ -1,14 +1,15 @@ -import { nextTestSetup } from 'e2e-utils' +import { FileRef, nextTestSetup } from 'e2e-utils' +import path from 'path' describe('referencing a client component in an app route', () => { const { next } = nextTestSetup({ - files: __dirname, + files: new FileRef(path.join(__dirname)), }) it('responds without error', async () => { expect(JSON.parse(await next.render('/runtime'))).toEqual({ - clientComponent: 'function', - myModuleClientComponent: 'function', + // Turbopack's proxy components are functions + clientComponent: process.env.TURBOPACK ? 'function' : 'object', }) }) }) diff --git a/test/e2e/app-dir/dynamic/app/dynamic/named-export/page.js b/test/e2e/app-dir/dynamic/app/dynamic/named-export/page.js index 3285b72c5f5596..b767273ab60776 100644 --- a/test/e2e/app-dir/dynamic/app/dynamic/named-export/page.js +++ b/test/e2e/app-dir/dynamic/app/dynamic/named-export/page.js @@ -2,7 +2,7 @@ import dynamic from 'next/dynamic' const Button = dynamic(() => import('./client').then((mod) => { - return { default: mod.Button } + return mod.Button }) )