From ca170fbc11f1095d8c99843046660a0ef401c678 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 9 May 2022 16:28:34 -0500 Subject: [PATCH] Move default root layout loading to view-loader --- .../build/webpack/loaders/next-view-loader.ts | 32 +++++++++----- packages/next/server/view-render.tsx | 17 +------- .../dashboard/another/page.server.js | 7 ++++ .../app/views/(newroot)/layout.server.js | 19 +++++++++ .../deployments/breakdown/page.server.js | 7 ++++ .../views/dashboard/(custom)/layout.server.js | 8 ++++ test/e2e/views-dir/index.test.ts | 42 ++++++++++++++++++- 7 files changed, 104 insertions(+), 28 deletions(-) create mode 100644 test/e2e/views-dir/app/views/(newroot)/dashboard/another/page.server.js create mode 100644 test/e2e/views-dir/app/views/(newroot)/layout.server.js create mode 100644 test/e2e/views-dir/app/views/dashboard/(custom)/deployments/breakdown/page.server.js create mode 100644 test/e2e/views-dir/app/views/dashboard/(custom)/layout.server.js diff --git a/packages/next/build/webpack/loaders/next-view-loader.ts b/packages/next/build/webpack/loaders/next-view-loader.ts index db07acd21f0d..4374b9ff3673 100644 --- a/packages/next/build/webpack/loaders/next-view-loader.ts +++ b/packages/next/build/webpack/loaders/next-view-loader.ts @@ -22,24 +22,34 @@ async function resolveLayoutPathsByPage({ }) { const layoutPaths = new Map() const parts = pagePath.split('/') - // if a new root is being created we shouldn't include `views/layout.js` - const shouldIncludeRootLayout = !parts.some( - (part) => part.startsWith('(') && part.endsWith(')') - ) - - for (let i = 1; i < parts.length; i++) { - if (i === 1 && !shouldIncludeRootLayout) continue + const isNewRootLayout = + parts[1]?.length > 2 && parts[1]?.startsWith('(') && parts[1]?.endsWith(')') + for (let i = parts.length; i >= 0; i--) { const pathWithoutSlashLayout = parts.slice(0, i).join('/') - const layoutPath = `${pathWithoutSlashLayout}/layout` - - const resolvedLayoutPath = await resolve(layoutPath) + if (!pathWithoutSlashLayout) { + continue + } + const layoutPath = `${pathWithoutSlashLayout}/layout` + let resolvedLayoutPath = await resolve(layoutPath) let urlPath = pathToUrlPath(pathWithoutSlashLayout) + // if we are in a new root views/(root) and a custom root layout was + // not provided or a root layout views/layout is not present, we use + // a default root layout to provide the html/body tags + const isCustomRootLayout = isNewRootLayout && i === 2 + + if ((isCustomRootLayout || i === 1) && !resolvedLayoutPath) { + resolvedLayoutPath = await resolve('next/dist/lib/views-layout') + } layoutPaths.set(urlPath, resolvedLayoutPath) - } + // if we're in a new root layout don't add the top-level view/layout + if (isCustomRootLayout) { + break + } + } return layoutPaths } diff --git a/packages/next/server/view-render.tsx b/packages/next/server/view-render.tsx index 8dfbe7ac1522..8952c5f493aa 100644 --- a/packages/next/server/view-render.tsx +++ b/packages/next/server/view-render.tsx @@ -19,7 +19,6 @@ import { import { FlushEffectsContext } from '../shared/lib/flush-effects' import { isDynamicRoute } from '../shared/lib/router/utils' import { tryGetPreviewData } from './api-utils/node' -import DefaultRootLayout from '../lib/views-layout' const ReactDOMServer = process.env.__NEXT_REACT_ROOT ? require('react-dom/server.browser') @@ -241,20 +240,8 @@ export async function renderToHTML( return mod }) - // we need to add the default root layout when - // not rendering a sub-tree (flightRouterPath) - // and a root layout isn't already present views/layout.js or - // views/(new-root)/layout.js - let hasRootLayout = componentPaths.some( - (path) => path === '/' || path.match(/\/\(.*?\)$/) - ) const isSubtreeRender = components.length < componentPaths.length - if (!hasRootLayout && !isSubtreeRender) { - components.unshift({ Component: DefaultRootLayout }) - hasRootLayout = true - } - // Reads of this are cached on the `req` object, so this should resolve // instantly. There's no need to pass this data down from a previous // invoke, where we'd have to consider server & serverless. @@ -340,7 +327,7 @@ export async function renderToHTML( } // if this is the root layout pass children as bodyChildren prop - if (hasRootLayout && i === 0) { + if (!isSubtreeRender && i === 0) { return React.createElement(layout.Component, { ...props, headChildren: props.headChildren, @@ -369,7 +356,7 @@ export async function renderToHTML( // } } - const headChildren = hasRootLayout + const headChildren = !isSubtreeRender ? buildManifest.rootMainFiles.map((src) => (