From bc9ed9de984f86eb850a094b25b04787c0e71af2 Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Wed, 21 Jun 2023 13:16:21 +0200 Subject: [PATCH] router: support layout/special files as direct children of parallel routes (#51604) follow up on #51413 where I kinda forgot to support parsing layout files in sub routes in a parallel segment. This should fix it by making sure that we check at all level of the app loader tree and by creating an implicit inner `children` for all parallel slot link NEXT-1301 --- .../build/webpack/loaders/next-app-loader.ts | 20 ++++++++++++++----- .../parallel-layout/@groupslot/default.tsx | 1 + .../app/parallel-layout/@slot/page.tsx | 9 ++++++++- .../parallel-layout/@slot/subroute/layout.tsx | 8 ++++++++ .../parallel-layout/@slot/subroute/page.tsx | 3 +++ .../app/parallel-layout/default.tsx | 1 + .../parallel-routes-and-interception.test.ts | 11 ++++++++++ 7 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@groupslot/default.tsx create mode 100644 test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/layout.tsx create mode 100644 test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/page.tsx create mode 100644 test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/default.tsx 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 99c4378c13fd6..b3c7ae8293db7 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -52,6 +52,7 @@ const FILE_TYPES = { const GLOBAL_ERROR_FILE_TYPE = 'global-error' const PAGE_SEGMENT = 'page$' +const PARALLEL_CHILDREN_SEGMENT = 'children$' type DirResolver = (pathToResolve: string) => string type PathResolver = ( @@ -315,7 +316,8 @@ async function createTreeCodeFromPath( subSegmentPath.push( ...normalizedParallelSegments.filter( - (segment) => segment !== PAGE_SEGMENT + (segment) => + segment !== PAGE_SEGMENT && segment !== PARALLEL_CHILDREN_SEGMENT ) ) @@ -359,10 +361,17 @@ async function createTreeCodeFromPath( } } + let parallelSegmentKey = Array.isArray(parallelSegment) + ? parallelSegment[0] + : parallelSegment + + parallelSegmentKey = + parallelSegmentKey === PARALLEL_CHILDREN_SEGMENT + ? 'children' + : parallelSegmentKey + props[normalizeParallelKey(parallelKey)] = `[ - '${ - Array.isArray(parallelSegment) ? parallelSegment[0] : parallelSegment - }', + '${parallelSegmentKey}', ${subtreeCode}, { ${definedFilePaths @@ -483,7 +492,8 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { continue } if (isParallelRoute) { - matched[rest[0]] = rest.slice(1) + // we insert a special marker in order to also process layout/etc files at the slot level + matched[rest[0]] = [PARALLEL_CHILDREN_SEGMENT, ...rest.slice(1)] continue } diff --git a/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@groupslot/default.tsx b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@groupslot/default.tsx new file mode 100644 index 0000000000000..ad4e17b5767f9 --- /dev/null +++ b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@groupslot/default.tsx @@ -0,0 +1 @@ +export default () => null diff --git a/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/page.tsx b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/page.tsx index 5695dda668610..0a9d6b4e2985b 100644 --- a/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/page.tsx +++ b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/page.tsx @@ -1,3 +1,10 @@ +import Link from 'next/link' + export default function Page() { - return 'slot children' + return ( + <> +
slot children
+ parallel subroute + + ) } diff --git a/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/layout.tsx b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/layout.tsx new file mode 100644 index 0000000000000..e412712b0e3a3 --- /dev/null +++ b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/layout.tsx @@ -0,0 +1,8 @@ +export default ({ children }) => { + return ( +
+

parallel subroute layout

+ {children} +
+ ) +} diff --git a/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/page.tsx b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/page.tsx new file mode 100644 index 0000000000000..45f12b3d4fc6c --- /dev/null +++ b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/@slot/subroute/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return 'subroute children' +} diff --git a/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/default.tsx b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/default.tsx new file mode 100644 index 0000000000000..ad4e17b5767f9 --- /dev/null +++ b/test/e2e/app-dir/parallel-routes-and-interception/app/parallel-layout/default.tsx @@ -0,0 +1 @@ +export default () => null diff --git a/test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts b/test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts index f85e2f2448722..2d1fcfd57851e 100644 --- a/test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts +++ b/test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts @@ -248,6 +248,17 @@ createNextDescribe( () => browser.waitForElementByCss('#parallel-layout').text(), 'parallel layout' ) + + // navigate to /parallel-layout/subroute + await browser.elementByCss('[href="/parallel-layout/subroute"]').click() + await check( + () => browser.waitForElementByCss('#parallel-layout').text(), + 'parallel layout' + ) + await check( + () => browser.waitForElementByCss('#parallel-subroute').text(), + 'parallel subroute layout' + ) }) it('should only scroll to the parallel route that was navigated to', async () => {