From e8915deb7b7fcf4c11e1ba8638b1a09531b2733a Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 7 Apr 2022 18:16:28 +0200 Subject: [PATCH] detect node_module pkg --- .../loaders/next-flight-server-loader.ts | 45 +++++++++++++++---- .../app/components/nav.js | 4 -- .../app/components/shared.js | 5 ++- .../app/pages/external-imports.server.js | 4 +- .../test/rsc.js | 6 +-- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-flight-server-loader.ts b/packages/next/build/webpack/loaders/next-flight-server-loader.ts index 03c53831ad25..44608bbcc4d8 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -41,6 +41,7 @@ async function parseModuleInfo({ isClientCompilation, isServerComponent, isClientComponent, + resolver, }: { resourcePath: string source: string @@ -48,6 +49,7 @@ async function parseModuleInfo({ extensions: string[] isServerComponent: (name: string) => boolean isClientComponent: (name: string) => boolean + resolver: (req: string) => Promise }): Promise<{ source: string imports: string[] @@ -73,6 +75,16 @@ async function parseModuleInfo({ switch (node.type) { case 'ImportDeclaration': const importSource = node.source.value + const resolvedPath = await resolver(importSource) + const isNodeModuleImport = resolvedPath.includes('/node_modules/') + + // matching node_module package but excluding react cores since react is required to be shared + const isReactImports = [ + 'react', + 'react/jsx-runtime', + 'react/jsx-dev-runtime', + ].includes(importSource) + if (!isClientCompilation) { // Server compilation for .server.js. if (isServerComponent(importSource)) { @@ -92,13 +104,16 @@ async function parseModuleInfo({ imports.push(importSource) } else { // A shared component. It should be handled as a server component. - const serverImportSource = createFlightServerRequest( - importSource, - extensions - ) + const serverImportSource = isReactImports + ? importSource + : createFlightServerRequest(importSource, extensions) transformedSource += importDeclarations transformedSource += JSON.stringify(serverImportSource) - imports.push(importSource) + + // TODO: support handling RSC components from node_modules + if (!isNodeModuleImport) { + imports.push(importSource) + } } } else { // For the client compilation, we skip all modules imports but @@ -106,11 +121,12 @@ async function parseModuleInfo({ // have to be imported from either server or client components. if ( isServerComponent(importSource) || - hasFlightLoader(importSource, 'server') + hasFlightLoader(importSource, 'server') // || + // TODO: support handling RSC components from node_modules + // isNodeModuleImport ) { continue } - imports.push(importSource) } @@ -159,7 +175,16 @@ export default async function transformSource( source: string ): Promise { const { client: isClientCompilation, extensions } = this.getOptions() - const { resourcePath } = this + const { resourcePath, resolve: resolveFn, context } = this + + const resolver = (req: string): Promise => { + return new Promise((resolve, reject) => { + resolveFn(context, req, (err: any, result: string) => { + if (err) return reject(err) + resolve(result) + }) + }) + } if (typeof source !== 'string') { throw new Error('Expected source to have been transformed to a string.') @@ -192,6 +217,7 @@ export default async function transformSource( isClientCompilation, isServerComponent, isClientComponent, + resolver, }) /** @@ -234,5 +260,8 @@ export default async function transformSource( } const output = transformedSource + '\n' + buildExports(rscExports, isEsm) + // if (resourcePath.includes('external-imports')) { + // console.log(isClientCompilation ? 'client' : 'server', '\n' ,output) + // } return output } diff --git a/test/integration/react-streaming-and-server-components/app/components/nav.js b/test/integration/react-streaming-and-server-components/app/components/nav.js index e4f706cfbcb7..23fb83d933a3 100644 --- a/test/integration/react-streaming-and-server-components/app/components/nav.js +++ b/test/integration/react-streaming-and-server-components/app/components/nav.js @@ -1,12 +1,8 @@ import Link from 'next/link' -import { Text } from 'esm-client-component' export default function Nav() { return ( <> -
- -
next link diff --git a/test/integration/react-streaming-and-server-components/app/components/shared.js b/test/integration/react-streaming-and-server-components/app/components/shared.js index 8df6957913b9..f66f284b9c8a 100644 --- a/test/integration/react-streaming-and-server-components/app/components/shared.js +++ b/test/integration/react-streaming-and-server-components/app/components/shared.js @@ -1,6 +1,8 @@ import { useState } from 'react' import Client from './client.client' +const random = ~~(Math.random() * 10000) + export default function Shared() { let isServerComponent try { @@ -12,7 +14,8 @@ export default function Shared() { return ( <> - , {isServerComponent ? 'shared:server' : 'shared:client'} + ,{' '} + {(isServerComponent ? 'shared:server' : 'shared:client') + ':' + random} ) } diff --git a/test/integration/react-streaming-and-server-components/app/pages/external-imports.server.js b/test/integration/react-streaming-and-server-components/app/pages/external-imports.server.js index 40a41e569a75..78698b9fa948 100644 --- a/test/integration/react-streaming-and-server-components/app/pages/external-imports.server.js +++ b/test/integration/react-streaming-and-server-components/app/pages/external-imports.server.js @@ -1,11 +1,9 @@ -import moment from 'moment' import nonIsomorphicText from 'non-isomorphic-text' export default function Page() { return (
-
date:{moment().toString()}
-
{nonIsomorphicText()}
+
date:{nonIsomorphicText()}
) } diff --git a/test/integration/react-streaming-and-server-components/test/rsc.js b/test/integration/react-streaming-and-server-components/test/rsc.js index 01a8cfb13fb0..583dddc22182 100644 --- a/test/integration/react-streaming-and-server-components/test/rsc.js +++ b/test/integration/react-streaming-and-server-components/test/rsc.js @@ -56,8 +56,8 @@ export default function (context, { runtime, env }) { // Should have 2 occurrences of "shared:server", and 2 occurrences of // "shared:client". - const sharedServerModule = [...main.matchAll(/shared:server/g)] - const sharedClientModule = [...main.matchAll(/shared:client/g)] + const sharedServerModule = [...main.matchAll(/shared:server:(\d+)/g)] + const sharedClientModule = [...main.matchAll(/shared:client:(\d+)/g)] expect(sharedServerModule.length).toBe(2) expect(sharedClientModule.length).toBe(2) @@ -184,7 +184,7 @@ export default function (context, { runtime, env }) { .readFileSync(join(distServerDir, 'external-imports.js')) .toString() - expect(bundle).not.toContain('moment') + expect(bundle).not.toContain('non-isomorphic-text') }) }