diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index f7118a38a66e4..841ca3fd1500b 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -23,6 +23,7 @@ import { MiddlewareConfig } from '../../analysis/get-page-static-info' import { getFilenameAndExtension } from './next-metadata-route-loader' import { isAppBuiltinNotFoundPage } from '../../utils' import { loadEntrypoint } from '../../load-entrypoint' +import { isGroupSegment } from '../../../shared/lib/segment' export type AppLoaderOptions = { name: string @@ -76,10 +77,6 @@ export type ComponentsType = { readonly defaultPage?: ModuleReference } -function isGroupSegment(segment: string) { - return segment.startsWith('(') && segment.endsWith(')') -} - async function createAppRouteCode({ name, page, diff --git a/packages/next/src/client/components/router-reducer/compute-changed-path.ts b/packages/next/src/client/components/router-reducer/compute-changed-path.ts index 763b689083aa6..3a80a5a051b8a 100644 --- a/packages/next/src/client/components/router-reducer/compute-changed-path.ts +++ b/packages/next/src/client/components/router-reducer/compute-changed-path.ts @@ -1,7 +1,12 @@ import { FlightRouterState, Segment } from '../../../server/app-render/types' import { INTERCEPTION_ROUTE_MARKERS } from '../../../server/future/helpers/interception-routes' +import { isGroupSegment } from '../../../shared/lib/segment' import { matchSegment } from '../match-segments' +const removeLeadingSlash = (segment: string): string => { + return segment[0] === '/' ? segment.slice(1) : segment +} + const segmentToPathname = (segment: Segment): string => { if (typeof segment === 'string') { return segment @@ -10,13 +15,11 @@ const segmentToPathname = (segment: Segment): string => { return segment[1] } -function normalizePathname(pathname: string): string { +function normalizeSegments(segments: string[]): string { return ( - pathname.split('/').reduce((acc, segment) => { - if ( - segment === '' || - (segment.startsWith('(') && segment.endsWith(')')) - ) { + segments.reduce((acc, segment) => { + segment = removeLeadingSlash(segment) + if (segment === '' || isGroupSegment(segment)) { return acc } @@ -40,8 +43,7 @@ export function extractPathFromFlightRouterState( if (segment.startsWith('__PAGE__')) return '' - const path = [segment] - + const segments = [segment] const parallelRoutes = flightRouterState[1] ?? {} const childrenPath = parallelRoutes.children @@ -49,7 +51,7 @@ export function extractPathFromFlightRouterState( : undefined if (childrenPath !== undefined) { - path.push(childrenPath) + segments.push(childrenPath) } else { for (const [key, value] of Object.entries(parallelRoutes)) { if (key === 'children') continue @@ -57,13 +59,12 @@ export function extractPathFromFlightRouterState( const childPath = extractPathFromFlightRouterState(value) if (childPath !== undefined) { - path.push(childPath) + segments.push(childPath) } } } - // TODO-APP: optimise this, it's not ideal to join and split - return normalizePathname(path.join('/')) + return normalizeSegments(segments) } function computeChangedPathImpl( @@ -116,5 +117,5 @@ export function computeChangedPath( } // lightweight normalization to remove route groups - return normalizePathname(changedPath) + return normalizeSegments(changedPath.split('/')) } diff --git a/packages/next/src/shared/lib/router/utils/app-paths.ts b/packages/next/src/shared/lib/router/utils/app-paths.ts index 59273bdce4ac4..77612edf6d10a 100644 --- a/packages/next/src/shared/lib/router/utils/app-paths.ts +++ b/packages/next/src/shared/lib/router/utils/app-paths.ts @@ -1,4 +1,5 @@ import { ensureLeadingSlash } from '../../page-path/ensure-leading-slash' +import { isGroupSegment } from '../../segment' /** * Normalizes an app route so it represents the actual request path. Essentially @@ -28,7 +29,7 @@ export function normalizeAppPath(route: string) { } // Groups are ignored. - if (segment[0] === '(' && segment.endsWith(')')) { + if (isGroupSegment(segment)) { return pathname } diff --git a/packages/next/src/shared/lib/segment.ts b/packages/next/src/shared/lib/segment.ts new file mode 100644 index 0000000000000..6167d681ee6e1 --- /dev/null +++ b/packages/next/src/shared/lib/segment.ts @@ -0,0 +1,4 @@ +export function isGroupSegment(segment: string) { + // Use array[0] for performant purpose + return segment[0] === '(' && segment.endsWith(')') +}