From 7517feb8826caec78fdccf897e4bcf78c14081a0 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 16 Apr 2022 01:08:37 +0200 Subject: [PATCH 1/6] rsc: skip next builtin module when apply loaders --- .../webpack/loaders/next-flight-server-loader.ts | 8 ++++++-- packages/next/build/webpack/loaders/utils.ts | 12 ++++++------ .../build/webpack/plugins/flight-manifest-plugin.ts | 2 +- 3 files changed, 13 insertions(+), 9 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 4740a9197e19287..e84273e007b3a2b 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -5,6 +5,7 @@ import { buildExports, createClientComponentFilter, createServerComponentFilter, + isNextBuiltinClientComponent, } from './utils' function createFlightServerRequest(request: string, options: object) { @@ -57,7 +58,10 @@ async function parseModuleInfo({ const isBuiltinModule_ = builtinModules.includes(path) const resolvedPath = isBuiltinModule_ ? path : await resolver(path) - const isNodeModuleImport_ = resolvedPath.includes('/node_modules/') + const isNodeModuleImport_ = + /[\\/]node_modules[\\/]/.test(resolvedPath) && + // exclude next built-in modules + !isNextBuiltinClientComponent(resolvedPath) return [isBuiltinModule_, isNodeModuleImport_] as const } @@ -208,7 +212,7 @@ export default async function transformSource( } const isServerComponent = createServerComponentFilter(extensions) - const isClientComponent = createClientComponentFilter(extensions) + const isClientComponent = createClientComponentFilter() const hasAppliedFlightServerLoader = this.loaders.some((loader: any) => { return hasFlightLoader(loader.path, 'server') }) diff --git a/packages/next/build/webpack/loaders/utils.ts b/packages/next/build/webpack/loaders/utils.ts index 046a9b950e6e4b6..fc829383e89c188 100644 --- a/packages/next/build/webpack/loaders/utils.ts +++ b/packages/next/build/webpack/loaders/utils.ts @@ -1,4 +1,4 @@ -const defaultJsFileExtensions = ['js', 'mjs', 'jsx', 'ts', 'tsx', 'json'] +const defaultJsFileExtensions = ['js', 'mjs', 'jsx', 'ts', 'tsx'] const imageExtensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'] const nextClientComponents = ['link', 'image', 'head', 'script'] @@ -24,16 +24,14 @@ export function buildExports(moduleExports: any, isESM: boolean) { return ret } -export const createClientComponentFilter = ( - extensions: string[] = defaultJsFileExtensions -) => { +export const createClientComponentFilter = () => { // Special cases for Next.js APIs that are considered as client components: // - .client.[ext] // - next built-in client components // - .[imageExt] const regex = new RegExp( '(' + - `\\.client(\\.(${extensions.join('|')}))?|` + + `\\.client(\\.(${defaultJsFileExtensions.join('|')}))?|` + `next/(${nextClientComponents.join('|')})(\\.js)?|` + `\\.(${imageExtensions.join('|')})` + ')$' @@ -42,7 +40,9 @@ export const createClientComponentFilter = ( return (importSource: string) => regex.test(importSource) } -export const createServerComponentFilter = (extensions: string[]) => { +export const createServerComponentFilter = ( + extensions: string[] = defaultJsFileExtensions +) => { const regex = new RegExp(`\\.server(\\.(${extensions.join('|')}))?$`) return (importSource: string) => regex.test(importSource) } diff --git a/packages/next/build/webpack/plugins/flight-manifest-plugin.ts b/packages/next/build/webpack/plugins/flight-manifest-plugin.ts index d639b66ecf7e11a..73c82d8b7d322da 100644 --- a/packages/next/build/webpack/plugins/flight-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/flight-manifest-plugin.ts @@ -23,6 +23,7 @@ type Options = { const PLUGIN_NAME = 'FlightManifestPlugin' +const isClientComponent = createClientComponentFilter() export class FlightManifestPlugin { dev: boolean = false pageExtensions: string[] @@ -64,7 +65,6 @@ export class FlightManifestPlugin { createAsset(assets: any, compilation: any) { const manifest: any = {} - const isClientComponent = createClientComponentFilter(this.pageExtensions) compilation.chunkGroups.forEach((chunkGroup: any) => { function recordModule(id: string, _chunk: any, mod: any) { const resource = mod.resource From c1ac40ad403aceab3285ce1be358e3c3a432556d Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 16 Apr 2022 01:14:09 +0200 Subject: [PATCH 2/6] add test --- test/production/react-18-streaming-ssr/index.test.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/production/react-18-streaming-ssr/index.test.ts b/test/production/react-18-streaming-ssr/index.test.ts index 7bc84746ffc5f10..c1be4ac31930d08 100644 --- a/test/production/react-18-streaming-ssr/index.test.ts +++ b/test/production/react-18-streaming-ssr/index.test.ts @@ -11,7 +11,7 @@ describe('react 18 streaming SSR in minimal mode', () => { next = await createNext({ files: { 'pages/index.server.js': ` - export default function Page() { + export default function Page() { return

static streaming

} `, @@ -65,8 +65,15 @@ describe('react 18 streaming SSR with custom next configs', () => { } `, 'pages/hello.js': ` + import Link from 'next/link' + export default function Page() { - return

hello nextjs

+ return ( +
+

hello nextjs

+ home> +
+ ) } `, 'pages/multi-byte.js': ` @@ -114,6 +121,7 @@ describe('react 18 streaming SSR with custom next configs', () => { expect(redirectRes.status).toBe(308) expect(res.status).toBe(200) expect(html).toContain('hello nextjs') + expect(html).toContain('home') }) it('should render multi-byte characters correctly in streaming', async () => { From 1f04d45001b9129a990b278ddee7d531d849d737 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 16 Apr 2022 03:05:06 +0200 Subject: [PATCH 3/6] apply exts for server components --- .../loaders/next-flight-server-loader.ts | 20 ++++++++++--------- packages/next/build/webpack/loaders/utils.ts | 2 +- 2 files changed, 12 insertions(+), 10 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 e84273e007b3a2b..4b35f6d3727329f 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -6,10 +6,17 @@ import { createClientComponentFilter, createServerComponentFilter, isNextBuiltinClientComponent, + defaultJsFileExtensions, } from './utils' -function createFlightServerRequest(request: string, options: object) { - return `next-flight-server-loader?${JSON.stringify(options)}!${request}` +function createFlightServerRequest( + request: string, + options?: { client: 1 | undefined } +) { + return `next-flight-server-loader?${JSON.stringify({ + ...options, + extensions: defaultJsFileExtensions, + })}!${request}` } function hasFlightLoader(request: string, type: 'client' | 'server') { @@ -75,12 +82,7 @@ async function parseModuleInfo({ imports.push(path) } else { // Shared component. - imports.push( - createFlightServerRequest(path, { - extensions, - client: 1, - }) - ) + imports.push(createFlightServerRequest(path, { client: 1 })) } } @@ -123,7 +125,7 @@ async function parseModuleInfo({ const serverImportSource = isReactImports || isBuiltinModule ? importSource - : createFlightServerRequest(importSource, { extensions }) + : createFlightServerRequest(importSource) transformedSource += importDeclarations transformedSource += JSON.stringify(serverImportSource) diff --git a/packages/next/build/webpack/loaders/utils.ts b/packages/next/build/webpack/loaders/utils.ts index fc829383e89c188..5f88cc21f469b3e 100644 --- a/packages/next/build/webpack/loaders/utils.ts +++ b/packages/next/build/webpack/loaders/utils.ts @@ -1,4 +1,4 @@ -const defaultJsFileExtensions = ['js', 'mjs', 'jsx', 'ts', 'tsx'] +export const defaultJsFileExtensions = ['js', 'mjs', 'jsx', 'ts', 'tsx'] const imageExtensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'] const nextClientComponents = ['link', 'image', 'head', 'script'] From 26cf3b7efaf528ccc62e573bb59dc8a23e52ece0 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 16 Apr 2022 03:17:38 +0200 Subject: [PATCH 4/6] reduce params --- packages/next/build/webpack-config.ts | 4 ---- .../build/webpack/loaders/next-flight-server-loader.ts | 9 +++------ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 9166fefdf48343e..488c64fa5ea7c15 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1211,9 +1211,6 @@ export default async function getBaseWebpackConfig( ...rscCodeCondition, use: { loader: 'next-flight-server-loader', - options: { - extensions: rawPageExtensions, - }, }, }, ] @@ -1225,7 +1222,6 @@ export default async function getBaseWebpackConfig( loader: 'next-flight-server-loader', options: { client: 1, - extensions: rawPageExtensions, }, }, }, 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 4b35f6d3727329f..d8a40db3e6e1b5b 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -6,17 +6,15 @@ import { createClientComponentFilter, createServerComponentFilter, isNextBuiltinClientComponent, - defaultJsFileExtensions, } from './utils' function createFlightServerRequest( request: string, options?: { client: 1 | undefined } ) { - return `next-flight-server-loader?${JSON.stringify({ - ...options, - extensions: defaultJsFileExtensions, - })}!${request}` + return `next-flight-server-loader${ + options ? JSON.stringify(options) : '' + }!${request}` } function hasFlightLoader(request: string, type: 'client' | 'server') { @@ -26,7 +24,6 @@ function hasFlightLoader(request: string, type: 'client' | 'server') { async function parseModuleInfo({ resourcePath, source, - extensions, isClientCompilation, isServerComponent, isClientComponent, From 247fcd42bdcb2072a156e9bd52fb9463e1237d67 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 16 Apr 2022 03:43:00 +0200 Subject: [PATCH 5/6] rm ext arg --- .../build/webpack/loaders/next-flight-server-loader.ts | 10 +++------- packages/next/build/webpack/loaders/utils.ts | 8 ++++---- 2 files changed, 7 insertions(+), 11 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 d8a40db3e6e1b5b..7a386426460b794 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -12,9 +12,7 @@ function createFlightServerRequest( request: string, options?: { client: 1 | undefined } ) { - return `next-flight-server-loader${ - options ? JSON.stringify(options) : '' - }!${request}` + return `next-flight-server-loader${JSON.stringify(options)}!${request}` } function hasFlightLoader(request: string, type: 'client' | 'server') { @@ -32,7 +30,6 @@ async function parseModuleInfo({ resourcePath: string source: string isClientCompilation: boolean - extensions: string[] isServerComponent: (name: string) => boolean isClientComponent: (name: string) => boolean resolver: (req: string) => Promise @@ -194,7 +191,7 @@ export default async function transformSource( this: any, source: string ): Promise { - const { client: isClientCompilation, extensions } = this.getOptions() + const { client: isClientCompilation } = this.getOptions() const { resourcePath, resolve: resolveFn, context } = this const resolver = (req: string): Promise => { @@ -210,7 +207,7 @@ export default async function transformSource( throw new Error('Expected source to have been transformed to a string.') } - const isServerComponent = createServerComponentFilter(extensions) + const isServerComponent = createServerComponentFilter() const isClientComponent = createClientComponentFilter() const hasAppliedFlightServerLoader = this.loaders.some((loader: any) => { return hasFlightLoader(loader.path, 'server') @@ -234,7 +231,6 @@ export default async function transformSource( } = await parseModuleInfo({ resourcePath, source, - extensions, isClientCompilation, isServerComponent, isClientComponent, diff --git a/packages/next/build/webpack/loaders/utils.ts b/packages/next/build/webpack/loaders/utils.ts index 5f88cc21f469b3e..ba2c478b8af9a15 100644 --- a/packages/next/build/webpack/loaders/utils.ts +++ b/packages/next/build/webpack/loaders/utils.ts @@ -40,9 +40,9 @@ export const createClientComponentFilter = () => { return (importSource: string) => regex.test(importSource) } -export const createServerComponentFilter = ( - extensions: string[] = defaultJsFileExtensions -) => { - const regex = new RegExp(`\\.server(\\.(${extensions.join('|')}))?$`) +export const createServerComponentFilter = () => { + const regex = new RegExp( + `\\.server(\\.(${defaultJsFileExtensions.join('|')}))?$` + ) return (importSource: string) => regex.test(importSource) } From d3a04157734a78e0e9665c547c5287e6445d8343 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Sat, 16 Apr 2022 11:12:37 +0200 Subject: [PATCH 6/6] fix missing qmark --- .../next/build/webpack/loaders/next-flight-server-loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7a386426460b794..6436f92043f5cfd 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -12,7 +12,7 @@ function createFlightServerRequest( request: string, options?: { client: 1 | undefined } ) { - return `next-flight-server-loader${JSON.stringify(options)}!${request}` + return `next-flight-server-loader?${JSON.stringify(options)}!${request}` } function hasFlightLoader(request: string, type: 'client' | 'server') {