From 4453a11c714e7f4cc728a13291806940272528b6 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 12:04:00 -0700 Subject: [PATCH 1/9] polish webpack and add failed test --- packages/next/build/webpack-config.ts | 54 +++++------------------ packages/next/server/app-render.tsx | 5 +-- test/e2e/app-dir/app/app/internal/page.js | 4 ++ 3 files changed, 17 insertions(+), 46 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index a3bf3cf8169e467..0b4c643033249ff 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -2,7 +2,7 @@ import ReactRefreshWebpackPlugin from 'next/dist/compiled/@next/react-refresh-ut import chalk from 'next/dist/compiled/chalk' import crypto from 'crypto' import { webpack } from 'next/dist/compiled/webpack/webpack' -import path, { join as pathJoin, relative as relativePath } from 'path' +import path, { join as pathJoin, relative as relativePath, resolve } from 'path' import { escapeStringRegexp } from '../shared/lib/escape-regexp' import { DOT_NEXT_ALIAS, @@ -73,8 +73,7 @@ const babelIncludeRegexes: RegExp[] = [ /[\\/](strip-ansi|ansi-regex|styled-jsx)[\\/]/, ] -const staticGenerationAsyncStorageRegex = - /next[\\/]dist[\\/]client[\\/]components[\\/]static-generation-async-storage/ +const reactPackagesRegex = /^(react(?:$|\/)|react-dom(?:$|\/)|scheduler$)/ const BABEL_CONFIG_FILES = [ '.babelrc', @@ -136,14 +135,6 @@ function isResourceInPackages( ) } -const bundledReactImports = [ - 'react', - 'react-dom', - 'react/jsx-runtime', - 'react/jsx-dev-runtime', - 'next/dist/compiled/react-server-dom-webpack/server.browser', -] - export function getDefineEnv({ dev, config, @@ -1069,7 +1060,10 @@ export default async function getBaseWebpackConfig( // Special internal modules that must be bundled for Server Components. if (layer === WEBPACK_LAYERS.server) { - if (bundledReactImports.includes(request)) { + if ( + reactPackagesRegex.test(request) || + request === 'next/dist/compiled/react-server-dom-webpack/server.browser' + ) { return } } @@ -1082,7 +1076,7 @@ export default async function getBaseWebpackConfig( if (/^(?:next$)/.test(request)) { return `commonjs ${request}` } - if (/^(react(?:$|\/)|react-dom(?:$|\/))/.test(request)) { + if (reactPackagesRegex.test(request)) { // override react-dom to server-rendering-stub for server if (request === 'react-dom' && hasAppDir && !isClient) { request = 'react-dom/server-rendering-stub' @@ -1206,7 +1200,7 @@ export default async function getBaseWebpackConfig( // It doesn't matter what the extension is, as we'll transpile it anyway. if (config.experimental.transpilePackages && !resolvedExternalPackageDirs) { resolvedExternalPackageDirs = new Map() - // We need to reoslve all the external package dirs initially. + // We need to resolve all the external package dirs initially. for (const pkg of config.experimental.transpilePackages) { const pkgRes = await resolveExternal( dir, @@ -1241,22 +1235,13 @@ export default async function getBaseWebpackConfig( return } - // Treat react packages as external for SSR layer, - // then let require-hook mapping them to internals. + // Treat react packages and next internals as external for SSR layer, + // also map react to builtin ones with require-hook. if (layer === WEBPACK_LAYERS.client) { - if ( - [ - 'react', - 'react/jsx-runtime', - 'react/jsx-dev-runtime', - 'react-dom', - 'scheduler', - ].includes(request) - ) { + if (reactPackagesRegex.test(request)) { return `commonjs next/dist/compiled/${request}` - } else { - return } + return } if (shouldBeBundled) return @@ -1643,12 +1628,6 @@ export default async function getBaseWebpackConfig( }, ] : []), - ...[ - { - layer: WEBPACK_LAYERS.shared, - test: staticGenerationAsyncStorageRegex, - }, - ], // TODO: FIXME: do NOT webpack 5 support with this // x-ref: https://github.com/webpack/webpack/issues/11467 ...(!config.experimental.fullySpecified @@ -1677,12 +1656,6 @@ export default async function getBaseWebpackConfig( // RSC server compilation loaders { test: codeCondition.test, - include: [ - dir, - // To let the internal client components passing through flight loader - NEXT_PROJECT_ROOT_DIST, - ], - exclude: [staticGenerationAsyncStorageRegex], issuerLayer: WEBPACK_LAYERS.server, use: { loader: 'next-flight-loader', @@ -1715,8 +1688,6 @@ export default async function getBaseWebpackConfig( // Alias react for switching between default set and share subset. oneOf: [ { - // test: codeCondition.test, - exclude: [staticGenerationAsyncStorageRegex], issuerLayer: WEBPACK_LAYERS.server, test(req: string) { // If it's not a source code file, or has been opted out of @@ -1788,7 +1759,6 @@ export default async function getBaseWebpackConfig( { test: codeCondition.test, issuerLayer: WEBPACK_LAYERS.server, - exclude: [staticGenerationAsyncStorageRegex], use: useSWCLoader ? getSwcLoader({ isServerLayer: true }) : // When using Babel, we will have to add the SWC loader diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 41c4e74e2a761fd..ed9c30292463c87 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -3,16 +3,13 @@ import type { LoadComponentsReturnType } from './load-components' import type { ServerRuntime } from '../types' import type { FontLoaderManifest } from '../build/webpack/plugins/font-loader-manifest-plugin' -// TODO-APP: investigate why require-hook doesn't work for app-render - +// Import builtin react directly to avoid require cache conflicts import React, { use } from 'next/dist/compiled/react' - import { NotFound as DefaultNotFound } from '../client/components/error' // this needs to be required lazily so that `next-server` can set // the env before we require import ReactDOMServer from 'next/dist/compiled/react-dom/server.browser' - import { ParsedUrlQuery } from 'querystring' import { NextParsedUrlQuery } from './request-meta' import RenderResult from './render-result' diff --git a/test/e2e/app-dir/app/app/internal/page.js b/test/e2e/app-dir/app/app/internal/page.js index 525104c574ac8f6..22de6ce7175fe21 100644 --- a/test/e2e/app-dir/app/app/internal/page.js +++ b/test/e2e/app-dir/app/app/internal/page.js @@ -1,9 +1,13 @@ import Link from 'next/link' +import Head from 'next/head' export default function Page() { return (
+ + 123 + Navigate Rewrite From 142bcb5e1cd8c25b83a9e80e4e37456d24966628 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 12:23:39 -0700 Subject: [PATCH 2/9] don't apply customized external resolving for rsc layers --- packages/next/build/webpack-config.ts | 4 ++++ test/e2e/app-dir/app/app/internal/page.js | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 0b4c643033249ff..e33ed33570297e5 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1052,6 +1052,9 @@ export default async function getBaseWebpackConfig( // absolute paths. (process.platform === 'win32' && path.win32.isAbsolute(request)) + const isRscLayer = + layer === WEBPACK_LAYERS.server || layer === WEBPACK_LAYERS.client + // make sure import "next" shows a warning when imported // in pages/components if (request === 'next') { @@ -1107,6 +1110,7 @@ export default async function getBaseWebpackConfig( // we need to process shared `router/router` and `dynamic`, // so that the DefinePlugin can inject process.env values const isNextExternal = + !isRscLayer && /next[/\\]dist[/\\](shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic))/.test( localRes ) diff --git a/test/e2e/app-dir/app/app/internal/page.js b/test/e2e/app-dir/app/app/internal/page.js index 22de6ce7175fe21..134daec5bbb4f47 100644 --- a/test/e2e/app-dir/app/app/internal/page.js +++ b/test/e2e/app-dir/app/app/internal/page.js @@ -5,8 +5,9 @@ export default function Page() { return (
+ {/* NOTE: next/head will not work in RSC for now but not break either */} - 123 + internal-title Navigate Rewrite From 45de1aae8ed6d65b4a883cea0e251799125b16a9 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 12:31:52 -0700 Subject: [PATCH 3/9] revert change --- packages/next/build/webpack-config.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index e33ed33570297e5..85e01294a15adb5 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -75,6 +75,9 @@ const babelIncludeRegexes: RegExp[] = [ const reactPackagesRegex = /^(react(?:$|\/)|react-dom(?:$|\/)|scheduler$)/ +const staticGenerationAsyncStorageRegex = + /next[\\/]dist[\\/]client[\\/]components[\\/]static-generation-async-storage/ + const BABEL_CONFIG_FILES = [ '.babelrc', '.babelrc.json', @@ -1632,6 +1635,12 @@ export default async function getBaseWebpackConfig( }, ] : []), + ...[ + { + layer: WEBPACK_LAYERS.shared, + test: staticGenerationAsyncStorageRegex, + }, + ], // TODO: FIXME: do NOT webpack 5 support with this // x-ref: https://github.com/webpack/webpack/issues/11467 ...(!config.experimental.fullySpecified @@ -1660,6 +1669,7 @@ export default async function getBaseWebpackConfig( // RSC server compilation loaders { test: codeCondition.test, + exclude: [staticGenerationAsyncStorageRegex], issuerLayer: WEBPACK_LAYERS.server, use: { loader: 'next-flight-loader', @@ -1692,6 +1702,7 @@ export default async function getBaseWebpackConfig( // Alias react for switching between default set and share subset. oneOf: [ { + exclude: [staticGenerationAsyncStorageRegex], issuerLayer: WEBPACK_LAYERS.server, test(req: string) { // If it's not a source code file, or has been opted out of @@ -1763,6 +1774,7 @@ export default async function getBaseWebpackConfig( { test: codeCondition.test, issuerLayer: WEBPACK_LAYERS.server, + exclude: [staticGenerationAsyncStorageRegex], use: useSWCLoader ? getSwcLoader({ isServerLayer: true }) : // When using Babel, we will have to add the SWC loader From 384306b21f131b4dea7ba4ed3160109d148796d7 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 12:34:20 -0700 Subject: [PATCH 4/9] fix lint --- packages/next/build/webpack-config.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 85e01294a15adb5..0fcb675480c6b65 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -2,7 +2,7 @@ import ReactRefreshWebpackPlugin from 'next/dist/compiled/@next/react-refresh-ut import chalk from 'next/dist/compiled/chalk' import crypto from 'crypto' import { webpack } from 'next/dist/compiled/webpack/webpack' -import path, { join as pathJoin, relative as relativePath, resolve } from 'path' +import path from 'path' import { escapeStringRegexp } from '../shared/lib/escape-regexp' import { DOT_NEXT_ALIAS, @@ -62,9 +62,12 @@ import { SubresourceIntegrityPlugin } from './webpack/plugins/subresource-integr import { FontLoaderManifestPlugin } from './webpack/plugins/font-loader-manifest-plugin' import { getSupportedBrowsers } from './utils' -const NEXT_PROJECT_ROOT = pathJoin(__dirname, '..', '..') -const NEXT_PROJECT_ROOT_DIST = pathJoin(NEXT_PROJECT_ROOT, 'dist') -const NEXT_PROJECT_ROOT_DIST_CLIENT = pathJoin(NEXT_PROJECT_ROOT_DIST, 'client') +const NEXT_PROJECT_ROOT = path.join(__dirname, '..', '..') +const NEXT_PROJECT_ROOT_DIST = path.join(NEXT_PROJECT_ROOT, 'dist') +const NEXT_PROJECT_ROOT_DIST_CLIENT = path.join( + NEXT_PROJECT_ROOT_DIST, + 'client' +) const babelIncludeRegexes: RegExp[] = [ /next[\\/]dist[\\/](esm[\\/])?shared[\\/]lib/, @@ -132,7 +135,7 @@ function isResourceInPackages( ? resource.startsWith(packageDirMapping.get(p)! + path.sep) : resource.includes( path.sep + - pathJoin('node_modules', p.replace(/\//g, path.sep)) + + path.join('node_modules', p.replace(/\//g, path.sep)) + path.sep ) ) @@ -741,10 +744,12 @@ export default async function getBaseWebpackConfig( ), [CLIENT_STATIC_FILES_RUNTIME_AMP]: `./` + - relativePath( - dir, - pathJoin(NEXT_PROJECT_ROOT_DIST_CLIENT, 'dev', 'amp-dev') - ).replace(/\\/g, '/'), + path + .relative( + dir, + path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, 'dev', 'amp-dev') + ) + .replace(/\\/g, '/'), } : {}), [CLIENT_STATIC_FILES_RUNTIME_MAIN]: From 117c1a0cac87f6de38b5504de24f9876d8379fbc Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 13:35:04 -0700 Subject: [PATCH 5/9] mark app router context as client --- packages/next/shared/lib/app-router-context.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/next/shared/lib/app-router-context.ts b/packages/next/shared/lib/app-router-context.ts index d0a295d764faa4d..42eb5c0931612bb 100644 --- a/packages/next/shared/lib/app-router-context.ts +++ b/packages/next/shared/lib/app-router-context.ts @@ -1,3 +1,5 @@ +'use client' + import React from 'react' import type { FocusAndScrollRef } from '../../client/components/reducer' import type { FlightRouterState, FlightData } from '../../server/app-render' From 9cb123618453117bf9fb0ffaf8fcd322b8316970 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 15:24:19 -0700 Subject: [PATCH 6/9] bundle server layer but not client layer --- packages/next/build/webpack-config.ts | 43 ++++++++++--------- .../client/components/navigation/client.ts | 2 - .../client/components/navigation/index.ts | 1 + .../next/shared/lib/app-router-context.ts | 2 - 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 0fcb675480c6b65..238f6a2844773de 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -76,7 +76,8 @@ const babelIncludeRegexes: RegExp[] = [ /[\\/](strip-ansi|ansi-regex|styled-jsx)[\\/]/, ] -const reactPackagesRegex = /^(react(?:$|\/)|react-dom(?:$|\/)|scheduler$)/ +const reactPackagesRegex = /^(react(?:$|\/)|react-dom(?:$|\/))/ +// /^(react(?:$|\/)|react-dom(?:$|\/))/ const staticGenerationAsyncStorageRegex = /next[\\/]dist[\\/]client[\\/]components[\\/]static-generation-async-storage/ @@ -1060,9 +1061,6 @@ export default async function getBaseWebpackConfig( // absolute paths. (process.platform === 'win32' && path.win32.isAbsolute(request)) - const isRscLayer = - layer === WEBPACK_LAYERS.server || layer === WEBPACK_LAYERS.client - // make sure import "next" shows a warning when imported // in pages/components if (request === 'next') { @@ -1087,11 +1085,7 @@ export default async function getBaseWebpackConfig( if (/^(?:next$)/.test(request)) { return `commonjs ${request}` } - if (reactPackagesRegex.test(request)) { - // override react-dom to server-rendering-stub for server - if (request === 'react-dom' && hasAppDir && !isClient) { - request = 'react-dom/server-rendering-stub' - } + if (/^(react(?:$|\/)|react-dom(?:$|\/))/.test(request)) { return `commonjs ${hasAppDir ? 'next/dist/compiled/' : ''}${request}` } @@ -1118,10 +1112,12 @@ export default async function getBaseWebpackConfig( // we need to process shared `router/router` and `dynamic`, // so that the DefinePlugin can inject process.env values const isNextExternal = - !isRscLayer && - /next[/\\]dist[/\\](shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic))/.test( - localRes - ) + // Treat next internals as non-external for server layer + layer === WEBPACK_LAYERS.server + ? false + : /next[/\\]dist[/\\](shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic))/.test( + localRes + ) if (isNextExternal) { // Generate Next.js external import @@ -1631,10 +1627,8 @@ export default async function getBaseWebpackConfig( // react to the direct file path, not the package name. In that case the condition // will be ignored completely. react: 'next/dist/compiled/react', - 'react-dom$': isClient - ? 'next/dist/compiled/react-dom/index' - : 'next/dist/compiled/react-dom/server-rendering-stub', - 'react-dom/client$': 'next/dist/compiled/react-dom/client', + 'react-dom$': + 'next/dist/compiled/react-dom/server-rendering-stub', }, }, }, @@ -1733,14 +1727,23 @@ export default async function getBaseWebpackConfig( }, }, }, + { + issuerLayer: WEBPACK_LAYERS.client, + test: codeCondition.test, + resolve: { + alias: { + react: 'next/dist/compiled/react', + 'react-dom$': + 'next/dist/compiled/react-dom/server-rendering-stub', + }, + }, + }, { test: codeCondition.test, resolve: { alias: { react: 'next/dist/compiled/react', - 'react-dom$': isClient - ? 'next/dist/compiled/react-dom/index' - : 'next/dist/compiled/react-dom/server-rendering-stub', + 'react-dom$': 'next/dist/compiled/react-dom', 'react-dom/client$': 'next/dist/compiled/react-dom/client', }, diff --git a/packages/next/client/components/navigation/client.ts b/packages/next/client/components/navigation/client.ts index cc5666e1b0ef5e7..fe677aa9de4d1ac 100644 --- a/packages/next/client/components/navigation/client.ts +++ b/packages/next/client/components/navigation/client.ts @@ -1,5 +1,3 @@ -'use client' - import { useContext, useMemo } from 'react' import { SearchParamsContext, diff --git a/packages/next/client/components/navigation/index.ts b/packages/next/client/components/navigation/index.ts index ad8894d297758c6..af0d32813374629 100644 --- a/packages/next/client/components/navigation/index.ts +++ b/packages/next/client/components/navigation/index.ts @@ -1,3 +1,4 @@ +'use client' // useLayoutSegments() // Only the segments for the current place. ['children', 'dashboard', 'children', 'integrations'] -> /dashboard/integrations (/dashboard/layout.js would get ['children', 'dashboard', 'children', 'integrations']) import type { FlightRouterState } from '../../../server/app-render' diff --git a/packages/next/shared/lib/app-router-context.ts b/packages/next/shared/lib/app-router-context.ts index 42eb5c0931612bb..d0a295d764faa4d 100644 --- a/packages/next/shared/lib/app-router-context.ts +++ b/packages/next/shared/lib/app-router-context.ts @@ -1,5 +1,3 @@ -'use client' - import React from 'react' import type { FocusAndScrollRef } from '../../client/components/reducer' import type { FlightRouterState, FlightData } from '../../server/app-render' From 1ab6a12d6dc012fe440fafc82ae58ae72035f499 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 16:23:44 -0700 Subject: [PATCH 7/9] fix client mark --- .../client/components/hooks-client-context.ts | 2 + .../{navigation/client.ts => navigation.ts} | 80 ++++++++++++++++- .../client/components/navigation/index.ts | 86 ------------------- .../next/shared/lib/app-router-context.ts | 3 + .../next/shared/lib/server-inserted-html.tsx | 2 + 5 files changed, 85 insertions(+), 88 deletions(-) rename packages/next/client/components/{navigation/client.ts => navigation.ts} (53%) delete mode 100644 packages/next/client/components/navigation/index.ts diff --git a/packages/next/client/components/hooks-client-context.ts b/packages/next/client/components/hooks-client-context.ts index 3fdc5395a7cfc84..b34157d876df44a 100644 --- a/packages/next/client/components/hooks-client-context.ts +++ b/packages/next/client/components/hooks-client-context.ts @@ -1,3 +1,5 @@ +'use client' + import { createContext } from 'react' export const SearchParamsContext = createContext(null as any) diff --git a/packages/next/client/components/navigation/client.ts b/packages/next/client/components/navigation.ts similarity index 53% rename from packages/next/client/components/navigation/client.ts rename to packages/next/client/components/navigation.ts index fe677aa9de4d1ac..13148ac10a7fcee 100644 --- a/packages/next/client/components/navigation/client.ts +++ b/packages/next/client/components/navigation.ts @@ -1,10 +1,17 @@ +// useLayoutSegments() // Only the segments for the current place. ['children', 'dashboard', 'children', 'integrations'] -> /dashboard/integrations (/dashboard/layout.js would get ['children', 'dashboard', 'children', 'integrations']) + import { useContext, useMemo } from 'react' +import type { FlightRouterState } from '../../server/app-render' +import { + AppRouterContext, + LayoutRouterContext, +} from '../../shared/lib/app-router-context' import { SearchParamsContext, // ParamsContext, PathnameContext, // LayoutSegmentsContext, -} from '../hooks-client-context' +} from './hooks-client-context' const INTERNAL_URLSEARCHPARAMS_INSTANCE = Symbol( 'internal for urlsearchparams readonly' @@ -89,4 +96,73 @@ export function usePathname(): string { export { ServerInsertedHTMLContext, useServerInsertedHTML, -} from '../../../shared/lib/server-inserted-html' +} from '../../shared/lib/server-inserted-html' + +// TODO-APP: Move the other router context over to this one +/** + * Get the router methods. For example router.push('/dashboard') + */ +export function useRouter(): import('../../shared/lib/app-router-context').AppRouterInstance { + return useContext(AppRouterContext) +} + +// TODO-APP: handle parallel routes +function getSelectedLayoutSegmentPath( + tree: FlightRouterState, + parallelRouteKey: string, + first = true, + segmentPath: string[] = [] +): string[] { + let node: FlightRouterState + if (first) { + // Use the provided parallel route key on the first parallel route + node = tree[1][parallelRouteKey] + } else { + // After first parallel route prefer children, if there's no children pick the first parallel route. + const parallelRoutes = tree[1] + node = parallelRoutes.children ?? Object.values(parallelRoutes)[0] + } + + if (!node) return segmentPath + const segment = node[0] + const segmentValue = Array.isArray(segment) ? segment[1] : segment + if (!segmentValue) return segmentPath + + segmentPath.push(segmentValue) + + return getSelectedLayoutSegmentPath( + node, + parallelRouteKey, + false, + segmentPath + ) +} + +// TODO-APP: Expand description when the docs are written for it. +/** + * Get the canonical segment path from the current level to the leaf node. + */ +export function useSelectedLayoutSegments( + parallelRouteKey: string = 'children' +): string[] { + const { tree } = useContext(LayoutRouterContext) + return getSelectedLayoutSegmentPath(tree, parallelRouteKey) +} + +// TODO-APP: Expand description when the docs are written for it. +/** + * Get the segment below the current level + */ +export function useSelectedLayoutSegment( + parallelRouteKey: string = 'children' +): string { + const selectedLayoutSegments = useSelectedLayoutSegments(parallelRouteKey) + if (selectedLayoutSegments.length === 0) { + throw new Error('No selected layout segment below the current level') + } + + return selectedLayoutSegments[0] +} + +export { redirect } from './redirect' +export { notFound } from './not-found' diff --git a/packages/next/client/components/navigation/index.ts b/packages/next/client/components/navigation/index.ts deleted file mode 100644 index af0d32813374629..000000000000000 --- a/packages/next/client/components/navigation/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -'use client' -// useLayoutSegments() // Only the segments for the current place. ['children', 'dashboard', 'children', 'integrations'] -> /dashboard/integrations (/dashboard/layout.js would get ['children', 'dashboard', 'children', 'integrations']) - -import type { FlightRouterState } from '../../../server/app-render' -import { useContext } from 'react' - -import { - AppRouterContext, - LayoutRouterContext, -} from '../../../shared/lib/app-router-context' - -// TODO-APP: Move the other router context over to this one -/** - * Get the router methods. For example router.push('/dashboard') - */ -export function useRouter(): import('../../../shared/lib/app-router-context').AppRouterInstance { - return useContext(AppRouterContext) -} - -// TODO-APP: handle parallel routes -function getSelectedLayoutSegmentPath( - tree: FlightRouterState, - parallelRouteKey: string, - first = true, - segmentPath: string[] = [] -): string[] { - let node: FlightRouterState - if (first) { - // Use the provided parallel route key on the first parallel route - node = tree[1][parallelRouteKey] - } else { - // After first parallel route prefer children, if there's no children pick the first parallel route. - const parallelRoutes = tree[1] - node = parallelRoutes.children ?? Object.values(parallelRoutes)[0] - } - - if (!node) return segmentPath - const segment = node[0] - const segmentValue = Array.isArray(segment) ? segment[1] : segment - if (!segmentValue) return segmentPath - - segmentPath.push(segmentValue) - - return getSelectedLayoutSegmentPath( - node, - parallelRouteKey, - false, - segmentPath - ) -} - -// TODO-APP: Expand description when the docs are written for it. -/** - * Get the canonical segment path from the current level to the leaf node. - */ -export function useSelectedLayoutSegments( - parallelRouteKey: string = 'children' -): string[] { - const { tree } = useContext(LayoutRouterContext) - return getSelectedLayoutSegmentPath(tree, parallelRouteKey) -} - -// TODO-APP: Expand description when the docs are written for it. -/** - * Get the segment below the current level - */ -export function useSelectedLayoutSegment( - parallelRouteKey: string = 'children' -): string { - const selectedLayoutSegments = useSelectedLayoutSegments(parallelRouteKey) - if (selectedLayoutSegments.length === 0) { - throw new Error('No selected layout segment below the current level') - } - - return selectedLayoutSegments[0] -} - -export { redirect } from '../redirect' -export { notFound } from '../not-found' - -export { - useSearchParams, - usePathname, - ServerInsertedHTMLContext, - useServerInsertedHTML, -} from './client' diff --git a/packages/next/shared/lib/app-router-context.ts b/packages/next/shared/lib/app-router-context.ts index d0a295d764faa4d..20cf781fff0af06 100644 --- a/packages/next/shared/lib/app-router-context.ts +++ b/packages/next/shared/lib/app-router-context.ts @@ -1,3 +1,6 @@ +'use client' +'use client' + import React from 'react' import type { FocusAndScrollRef } from '../../client/components/reducer' import type { FlightRouterState, FlightData } from '../../server/app-render' diff --git a/packages/next/shared/lib/server-inserted-html.tsx b/packages/next/shared/lib/server-inserted-html.tsx index 1bb4e1fc735a83a..c095e18150088ac 100644 --- a/packages/next/shared/lib/server-inserted-html.tsx +++ b/packages/next/shared/lib/server-inserted-html.tsx @@ -1,3 +1,5 @@ +'use client' + import React, { useContext } from 'react' export type ServerInsertedHTMLHook = (callbacks: () => React.ReactNode) => void From ab4b4809ed322f20815cf642d64cb9a489ceeb11 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 16:26:29 -0700 Subject: [PATCH 8/9] remove debug --- packages/next/build/webpack-config.ts | 1 - packages/next/shared/lib/app-router-context.ts | 1 - test/.stats-app/next.config.js | 12 ++---------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 238f6a2844773de..1d20fa66501a337 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -77,7 +77,6 @@ const babelIncludeRegexes: RegExp[] = [ ] const reactPackagesRegex = /^(react(?:$|\/)|react-dom(?:$|\/))/ -// /^(react(?:$|\/)|react-dom(?:$|\/))/ const staticGenerationAsyncStorageRegex = /next[\\/]dist[\\/]client[\\/]components[\\/]static-generation-async-storage/ diff --git a/packages/next/shared/lib/app-router-context.ts b/packages/next/shared/lib/app-router-context.ts index 20cf781fff0af06..42eb5c0931612bb 100644 --- a/packages/next/shared/lib/app-router-context.ts +++ b/packages/next/shared/lib/app-router-context.ts @@ -1,5 +1,4 @@ 'use client' -'use client' import React from 'react' import type { FocusAndScrollRef } from '../../client/components/reducer' diff --git a/test/.stats-app/next.config.js b/test/.stats-app/next.config.js index 8b5a00c9a9c06c0..cfa3ac3d7aa94b3 100644 --- a/test/.stats-app/next.config.js +++ b/test/.stats-app/next.config.js @@ -1,13 +1,5 @@ -// module.exports = { -// experimental: { -// appDir: true -// } -// } -const withBundleAnalyzer = require('@next/bundle-analyzer')({ - enabled: process.env.ANALYZE === 'true', -}) -module.exports = withBundleAnalyzer({ +module.exports = { experimental: { appDir: true, }, -}) +} From 53f73403fb310c9d1bffad2616eab157a8ea1896 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Mon, 24 Oct 2022 17:30:46 -0700 Subject: [PATCH 9/9] fix client layer bundle --- packages/next/build/webpack-config.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 1d20fa66501a337..cadad4bf7a5ed3b 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1084,7 +1084,15 @@ export default async function getBaseWebpackConfig( if (/^(?:next$)/.test(request)) { return `commonjs ${request}` } + if (/^(react(?:$|\/)|react-dom(?:$|\/))/.test(request)) { + // override react-dom to server-rendering-stub for server + if ( + request === 'react-dom' && + (layer === WEBPACK_LAYERS.client || layer === WEBPACK_LAYERS.server) + ) { + request = 'react-dom/server-rendering-stub' + } return `commonjs ${hasAppDir ? 'next/dist/compiled/' : ''}${request}` } @@ -1133,7 +1141,7 @@ export default async function getBaseWebpackConfig( .replace(/\\/g, '/') ) return `commonjs ${externalRequest}` - } else { + } else if (layer !== WEBPACK_LAYERS.client) { // We don't want to retry local requests // with other preferEsm options return