Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 23 additions & 24 deletions packages/next/src/client/components/layout-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import { hasInterceptionRouteInCurrentTree } from './router-reducer/reducers/has
import { dispatchAppRouterAction } from './use-action-queue'
import { useRouterBFCache, type RouterBFCacheEntry } from './bfcache'
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'
import { PAGE_SEGMENT_KEY } from '../../shared/lib/segment'
import {
NavigationPromisesContext,
type NavigationPromises,
Expand Down Expand Up @@ -348,7 +347,7 @@ function InnerLayoutRouter({
}: {
tree: FlightRouterState
segmentPath: FlightSegmentPath
debugNameContext: ActivityProps['name']
debugNameContext: string
cacheNode: CacheNode
params: Params
url: string
Expand Down Expand Up @@ -584,7 +583,7 @@ export default function OuterLayoutRouter({
parentParams,
url,
isActive,
debugNameContext: parentDebugNameContext,
debugNameContext,
} = context

// Get the CacheNode for this segment by reading it from the parent segment's
Expand Down Expand Up @@ -706,9 +705,20 @@ export default function OuterLayoutRouter({

const debugName = getBoundaryDebugNameFromSegment(segment)
// `debugNameContext` represents the nearest non-"virtual" parent segment.
// `getBoundaryDebugNameFromSegment` returns null for virtual segments.
// So if `debugName` is null, the context is passed through unchanged.
const debugNameContext = debugName ?? parentDebugNameContext
// `getBoundaryDebugNameFromSegment` returns undefined for virtual segments.
// So if `debugName` is undefined, the context is passed through unchanged.
const childDebugNameContext = debugName ?? debugNameContext

// In practical terms, clicking this name in the Suspense DevTools
// should select the child slots of that layout.
//
// So the name we apply to the Activity boundary is actually based on
// the nearest parent segments.
//
// We skip over "virtual" parents, i.e. ones inserted by Next.js that
// don't correspond to application-defined code.
const isVirtual = debugName === undefined
const debugNameToDisplay = isVirtual ? undefined : debugNameContext

// TODO: The loading module data for a segment is stored on the parent, then
// applied to each of that parent segment's parallel route slots. In the
Expand All @@ -729,7 +739,10 @@ export default function OuterLayoutRouter({
errorStyles={errorStyles}
errorScripts={errorScripts}
>
<LoadingBoundary name={debugName} loading={loadingModuleData}>
<LoadingBoundary
name={debugNameToDisplay}
loading={loadingModuleData}
>
<HTTPAccessFallbackBoundary
notFound={notFound}
forbidden={forbidden}
Expand All @@ -742,7 +755,7 @@ export default function OuterLayoutRouter({
params={params}
cacheNode={cacheNode}
segmentPath={segmentPath}
debugNameContext={debugNameContext}
debugNameContext={childDebugNameContext}
isActive={isActive && stateKey === activeStateKey}
/>
{segmentBoundaryTriggerNode}
Expand Down Expand Up @@ -775,15 +788,7 @@ export default function OuterLayoutRouter({
if (process.env.__NEXT_CACHE_COMPONENTS) {
child = (
<Activity
// In practical terms, clicking this name in the Suspense DevTools
// should select the child slots of that layout.
//
// So the name we apply to the Activity boundary is actually based on
// the nearest parent segments.
//
// We skip over "virtual" parents, i.e. ones inserted by Next.js that
// don't correspond to application-defined code.
name={debugNameContext}
name={debugNameToDisplay}
key={stateKey}
mode={stateKey === activeStateKey ? 'visible' : 'hidden'}
>
Expand Down Expand Up @@ -821,12 +826,6 @@ function isVirtualLayout(segment: string): boolean {
// This is inserted by the loader. We should consider encoding these
// in a more special way instead of checking the name, to distinguish them
// from app-defined groups.
segment === '(slot)' ||
// For some reason, the loader tree sometimes includes extra __PAGE__
// "layouts" when part of a parallel route. But it's not a leaf node.
// Otherwise, we wouldn't need this special case because pages are
// always leaf nodes.
// TODO: Investigate why the loader produces these fake page segments.
segment.startsWith(PAGE_SEGMENT_KEY)
segment === '(slot)'
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const LayoutRouterContext = React.createContext<{
parentCacheNode: CacheNode
parentSegmentPath: FlightSegmentPath | null
parentParams: Params
debugNameContext: string | undefined
debugNameContext: string
url: string
isActive: boolean
} | null>(null)
Expand Down
34 changes: 17 additions & 17 deletions test/development/acceptance-app/hydration-error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="text-misma..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -107,7 +107,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-elem..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -145,7 +145,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name="(extra-att..." loading={null}>
<LoadingBoundary name="/" loading={null}>
<HTTPAccessFallbackBoundary notFound={<SegmentViewNode>} forbidden={undefined} unauthorized={undefined}>
<HTTPAccessFallbackErrorBoundary pathname="/extra-att..." notFound={<SegmentViewNode>} ...>
<RedirectBoundary>
Expand Down Expand Up @@ -181,7 +181,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name="(extra-att..." loading={null}>
<LoadingBoundary name="/" loading={null}>
<HTTPAccessFallbackBoundary notFound={<SegmentViewNode>} forbidden={undefined} unauthorized={undefined}>
<HTTPAccessFallbackErrorBoundary pathname="/extra-att..." notFound={<SegmentViewNode>} ...>
<RedirectBoundary>
Expand Down Expand Up @@ -221,7 +221,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-text..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -262,7 +262,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-elem..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -300,7 +300,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-text..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -342,7 +342,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-text..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -376,7 +376,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-text..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -415,7 +415,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-whit..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -453,7 +453,7 @@ describe('Error overlay for hydration errors in App router', () => {
"componentStack": "...
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="extra-node..." loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -510,7 +510,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="p-under-p/" loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -566,7 +566,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="div-under-p/" loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -625,7 +625,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="tr-under-div/" loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -682,7 +682,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name={undefined} loading={null}>
<LoadingBoundary name="bad-nesting/" loading={null}>
<HTTPAccessFallbackBoundary notFound={undefined} forbidden={undefined} unauthorized={undefined}>
<RedirectBoundary>
<RedirectErrorBoundary router={{...}}>
Expand Down Expand Up @@ -902,7 +902,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name="(script-un..." loading={null}>
<LoadingBoundary name="/" loading={null}>
<HTTPAccessFallbackBoundary notFound={<SegmentViewNode>} forbidden={undefined} unauthorized={undefined}>
<HTTPAccessFallbackErrorBoundary pathname="/script-un..." notFound={<SegmentViewNode>} ...>
<RedirectBoundary>
Expand Down Expand Up @@ -966,7 +966,7 @@ describe('Error overlay for hydration errors in App router', () => {
<ScrollAndFocusHandler segmentPath={[...]}>
<InnerScrollAndFocusHandler segmentPath={[...]} focusAndScrollRef={{apply:false, ...}}>
<ErrorBoundary errorComponent={undefined} errorStyles={undefined} errorScripts={undefined}>
<LoadingBoundary name="(script-un..." loading={null}>
<LoadingBoundary name="/" loading={null}>
<HTTPAccessFallbackBoundary notFound={<SegmentViewNode>} forbidden={undefined} unauthorized={undefined}>
<HTTPAccessFallbackErrorBoundary pathname="/script-un..." notFound={<SegmentViewNode>} ...>
<RedirectBoundary>
Expand Down
Loading
Loading