Skip to content

Commit

Permalink
Remove segmentPath from RSC payload (#73827)
Browse files Browse the repository at this point in the history
Based on:

- #73826 

---

This removes the `segmentPath` prop from the LayoutRouter payload. This
can be derived on the client from the FlightRouterState instead.
  • Loading branch information
acdlite authored Dec 12, 2024
1 parent 48e9b8c commit 546f022
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 47 deletions.
1 change: 1 addition & 0 deletions packages/next/src/client/components/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ function Router({
return {
parentTree: tree,
parentCacheNode: cache,
parentSegmentPath: null,
// Root node always has `url`
// Provided in AppTreeContext to ensure it can be overwritten in layout-router
url: canonicalUrl,
Expand Down
14 changes: 11 additions & 3 deletions packages/next/src/client/components/layout-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ function InnerLayoutRouter({
value={{
parentTree: tree,
parentCacheNode: cacheNode,
parentSegmentPath: segmentPath,

// TODO-APP: overriding of url for parallel routes
url: url,
Expand Down Expand Up @@ -473,7 +474,6 @@ function LoadingBoundary({
*/
export default function OuterLayoutRouter({
parallelRouterKey,
segmentPath,
error,
errorStyles,
errorScripts,
Expand All @@ -485,7 +485,6 @@ export default function OuterLayoutRouter({
unauthorized,
}: {
parallelRouterKey: string
segmentPath: FlightSegmentPath
error: ErrorComponent | undefined
errorStyles: React.ReactNode | undefined
errorScripts: React.ReactNode | undefined
Expand All @@ -501,7 +500,7 @@ export default function OuterLayoutRouter({
throw new Error('invariant expected layout router to be mounted')
}

const { parentTree, parentCacheNode, url } = context
const { parentTree, parentCacheNode, parentSegmentPath, url } = context

// Get the CacheNode for this segment by reading it from the parent segment's
// child map.
Expand All @@ -516,9 +515,18 @@ export default function OuterLayoutRouter({

// Get the active segment in the tree
// The reason arrays are used in the data format is that these are transferred from the server to the browser so it's optimized to save bytes.
const parentTreeSegment = parentTree[0]
const tree = parentTree[1][parallelRouterKey]
const treeSegment = tree[0]

const segmentPath =
parentSegmentPath === null
? // TODO: The root segment value is currently omitted from the segment
// path. This has led to a bunch of special cases scattered throughout
// the code. We should clean this up.
[parallelRouterKey]
: parentSegmentPath.concat([parentTreeSegment, parallelRouterKey])

// The "state" key of a segment is the one passed to React — it represents the
// identity of the UI tree. Whenever the state key changes, the tree is
// recreated and the state is reset. In the App Router model, search params do
Expand Down
7 changes: 0 additions & 7 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {
ActionResult,
DynamicParamTypesShort,
FlightRouterState,
FlightSegmentPath,
RenderOpts,
Segment,
CacheNodeSeedData,
Expand Down Expand Up @@ -309,8 +308,6 @@ function createNotFoundLoaderTree(loaderTree: LoaderTree): LoaderTree {
]
}

export type CreateSegmentPath = (child: FlightSegmentPath) => FlightSegmentPath

/**
* Returns a function that parses the dynamic segment and return the associated value.
*/
Expand Down Expand Up @@ -466,11 +463,9 @@ async function generateDynamicRSCPayload(
flightData = (
await walkTreeWithFlightRouterState({
ctx,
createSegmentPath: (child) => child,
loaderTreeToFilter: loaderTree,
parentParams: {},
flightRouterState,
isFirst: true,
// For flight, render metadata inside leaf page
rscPayloadHead: (
<React.Fragment key={flightDataPathHeadKey}>
Expand Down Expand Up @@ -759,10 +754,8 @@ async function getRSCPayload(

const seedData = await createComponentTree({
ctx,
createSegmentPath: (child) => child,
loaderTree: tree,
parentParams: {},
firstItem: true,
injectedCSS,
injectedJS,
injectedFontPreloadTags,
Expand Down
22 changes: 2 additions & 20 deletions packages/next/src/server/app-render/create-component-tree.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import type {
FlightSegmentPath,
CacheNodeSeedData,
PreloadCallbacks,
} from './types'
import type { CacheNodeSeedData, PreloadCallbacks } from './types'
import React from 'react'
import { isClientReference } from '../../lib/client-reference'
import { getLayoutOrPageModule } from '../lib/app-dir-module'
import type { LoaderTree } from '../lib/app-dir-module'
import { interopDefault } from './interop-default'
import { parseLoaderTree } from './parse-loader-tree'
import type { CreateSegmentPath, AppRenderContext } from './app-render'
import type { AppRenderContext } from './app-render'
import { createComponentStylesAndScripts } from './create-component-styles-and-scripts'
import { getLayerAssets } from './get-layer-assets'
import { hasLoadingComponentInTree } from './has-loading-component-in-tree'
Expand All @@ -27,11 +23,9 @@ import { OUTLET_BOUNDARY_NAME } from '../../lib/metadata/metadata-constants'
* Use the provided loader tree to create the React Component tree.
*/
export function createComponentTree(props: {
createSegmentPath: CreateSegmentPath
loaderTree: LoaderTree
parentParams: Params
rootLayoutIncluded: boolean
firstItem?: boolean
injectedCSS: Set<string>
injectedJS: Set<string>
injectedFontPreloadTags: Set<string>
Expand Down Expand Up @@ -63,10 +57,8 @@ function errorMissingDefaultExport(
const cacheNodeKey = 'c'

async function createComponentTreeInternal({
createSegmentPath,
loaderTree: tree,
parentParams,
firstItem,
rootLayoutIncluded,
injectedCSS,
injectedJS,
Expand All @@ -77,11 +69,9 @@ async function createComponentTreeInternal({
preloadCallbacks,
authInterrupts,
}: {
createSegmentPath: CreateSegmentPath
loaderTree: LoaderTree
parentParams: Params
rootLayoutIncluded: boolean
firstItem?: boolean
injectedCSS: Set<string>
injectedJS: Set<string>
injectedFontPreloadTags: Set<string>
Expand Down Expand Up @@ -412,10 +402,6 @@ async function createComponentTreeInternal({
parallelRouteKey
): Promise<[string, React.ReactNode, CacheNodeSeedData | null]> => {
const isChildrenRouteKey = parallelRouteKey === 'children'
const currentSegmentPath: FlightSegmentPath = firstItem
? [parallelRouteKey]
: [actualSegment, parallelRouteKey]

const parallelRoute = parallelRoutes[parallelRouteKey]

const notFoundComponent =
Expand Down Expand Up @@ -489,9 +475,6 @@ async function createComponentTreeInternal({
}

const seedData = await createComponentTreeInternal({
createSegmentPath: (child) => {
return createSegmentPath([...currentSegmentPath, ...child])
},
loaderTree: parallelRoute,
parentParams: currentParams,
rootLayoutIncluded: rootLayoutIncludedAtThisLevelOrAbove,
Expand All @@ -517,7 +500,6 @@ async function createComponentTreeInternal({
parallelRouteKey,
<LayoutRouter
parallelRouterKey={parallelRouteKey}
segmentPath={createSegmentPath(currentSegmentPath)}
// TODO-APP: Add test for loading returning `undefined`. This currently can't be tested as the `webdriver()` tab will wait for the full page to load before returning.
error={ErrorComponent}
errorStyles={errorStyles}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {
FlightDataPath,
FlightDataSegment,
FlightRouterState,
FlightSegmentPath,
PreloadCallbacks,
Segment,
} from './types'
Expand All @@ -14,7 +13,7 @@ import type { LoaderTree } from '../lib/app-dir-module'
import { getLinkAndScriptTags } from './get-css-inlined-link-tags'
import { getPreloadableFonts } from './get-preloadable-fonts'
import { createFlightRouterStateFromLoaderTree } from './create-flight-router-state-from-loader-tree'
import type { CreateSegmentPath, AppRenderContext } from './app-render'
import type { AppRenderContext } from './app-render'
import { hasLoadingComponentInTree } from './has-loading-component-in-tree'
import {
DEFAULT_SEGMENT_KEY,
Expand All @@ -27,10 +26,8 @@ import { createComponentTree } from './create-component-tree'
* This can either be the common layout between two pages or a specific place to start rendering from using the "refetch" marker in the tree.
*/
export async function walkTreeWithFlightRouterState({
createSegmentPath,
loaderTreeToFilter,
parentParams,
isFirst,
flightRouterState,
parentRendered,
rscPayloadHead,
Expand All @@ -42,10 +39,8 @@ export async function walkTreeWithFlightRouterState({
ctx,
preloadCallbacks,
}: {
createSegmentPath: CreateSegmentPath
loaderTreeToFilter: LoaderTree
parentParams: { [key: string]: string | string[] }
isFirst: boolean
flightRouterState?: FlightRouterState
parentRendered?: boolean
rscPayloadHead: React.ReactNode
Expand Down Expand Up @@ -159,10 +154,8 @@ export async function walkTreeWithFlightRouterState({
// This ensures flightRouterPath is valid and filters down the tree
{
ctx,
createSegmentPath,
loaderTree: loaderTreeToFilter,
parentParams: currentParams,
firstItem: isFirst,
injectedCSS,
injectedJS,
injectedFontPreloadTags,
Expand Down Expand Up @@ -216,21 +209,13 @@ export async function walkTreeWithFlightRouterState({
for (const parallelRouteKey of parallelRoutesKeys) {
const parallelRoute = parallelRoutes[parallelRouteKey]

const currentSegmentPath: FlightSegmentPath = isFirst
? [parallelRouteKey]
: [actualSegment, parallelRouteKey]

const subPaths = await walkTreeWithFlightRouterState({
ctx,
createSegmentPath: (child) => {
return createSegmentPath([...currentSegmentPath, ...child])
},
loaderTreeToFilter: parallelRoute,
parentParams: currentParams,
flightRouterState:
flightRouterState && flightRouterState[1][parallelRouteKey],
parentRendered: parentRendered || renderComponentsOnThisLevel,
isFirst: false,
rscPayloadHead,
injectedCSS: injectedCSSWithCurrentLayout,
injectedJS: injectedJSWithCurrentLayout,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import type {
PrefetchKind,
RouterChangeByServerResponse,
} from '../../client/components/router-reducer/router-reducer-types'
import type { FlightRouterState } from '../../server/app-render/types'
import type {
FlightRouterState,
FlightSegmentPath,
} from '../../server/app-render/types'
import React from 'react'

export type ChildSegmentMap = Map<string, CacheNode>
Expand Down Expand Up @@ -148,6 +151,7 @@ export const AppRouterContext = React.createContext<AppRouterInstance | null>(
export const LayoutRouterContext = React.createContext<{
parentTree: FlightRouterState
parentCacheNode: CacheNode
parentSegmentPath: FlightSegmentPath | null
url: string
} | null>(null)

Expand Down

0 comments on commit 546f022

Please sign in to comment.