Skip to content

Commit 1af1a28

Browse files
authored
Delete abandoned segment parsing code (#82458)
Originally, as part of the clientParamParsing feature, I expected that I would omit param values from the FlightRouterState when sending data from the server, and add it on the client. However, I've since realized this is unnecessary because FlightRouterState is only used during runtime server responses. Not in static responses, like per-segment prefetches. Since the goal of clientParamParsing is to omit param values from static responses, we don't need to change anything about FlightRouterState. We may still want to update how params are processed on the server to more closely match the implementation on the client, but that still doesn't require any changes to FlightRouterState. So, this deletes all the code related to adding client-parsed params to FlightRouterState on the client. None of this was being used anywhere; it was added by previous PRs in anticipation that it would eventually be used. But now we don't need it.
1 parent 63cdc65 commit 1af1a28

File tree

8 files changed

+46
-203
lines changed

8 files changed

+46
-203
lines changed

packages/next/src/client/components/router-reducer/create-initial-router-state.ts

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,7 @@ export function createInitialRouterState({
3838
// as a URL that should be crawled.
3939
const initialCanonicalUrl = initialCanonicalUrlParts.join('/')
4040

41-
// TODO: Eventually we want to always read the rendered params from the URL
42-
// and/or the x-rewritten-path header, so that we can omit them from the
43-
// response body. This lets reuse cached responses if params aren't referenced
44-
// anywhere in the actual page data, e.g. if they're only accessed by client
45-
// components. However, during the initial render, there's no way to access
46-
// the headers. For a partially dynamic page, this is OK, because there's
47-
// going to be a dynamic server render regardless, so we can send the URL
48-
// in the resume body. For a completely static page, though, there's no
49-
// dynamic server render, so that won't work.
50-
//
51-
// Instead, we'll perform a HEAD request and read the rewritten URL from
52-
// that response.
53-
const renderedPathname = new URL(initialCanonicalUrl, 'http://localhost')
54-
.pathname
55-
56-
const normalizedFlightData = getFlightDataPartsFromPath(
57-
initialFlightData[0],
58-
renderedPathname
59-
)
41+
const normalizedFlightData = getFlightDataPartsFromPath(initialFlightData[0])
6042
const {
6143
tree: initialTree,
6244
seedData: initialSeedData,

packages/next/src/client/components/router-reducer/fetch-server-response.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ import {
3131
} from '../../flight-data-helpers'
3232
import { getAppBuildId } from '../../app-build-id'
3333
import { setCacheBustingSearchParam } from './set-cache-busting-search-param'
34-
import {
35-
getRenderedPathname,
36-
urlToUrlWithoutFlightMarker,
37-
} from '../../route-params'
34+
import { urlToUrlWithoutFlightMarker } from '../../route-params'
3835

3936
const createFromReadableStream =
4037
createFromReadableStreamBrowser as (typeof import('react-server-dom-webpack/client.browser'))['createFromReadableStream']
@@ -224,21 +221,8 @@ export async function fetchServerResponse(
224221
return doMpaNavigation(res.url)
225222
}
226223

227-
let renderedPathname
228-
if (process.env.__NEXT_CLIENT_SEGMENT_CACHE) {
229-
// Read the URL from the response object.
230-
renderedPathname = getRenderedPathname(res)
231-
} else {
232-
// Before Segment Cache is enabled, we should not rely on the new
233-
// rewrite headers (x-rewritten-path, x-rewritten-query) because that
234-
// is a breaking change. Read the URL from the response body.
235-
const renderedUrlParts = response.c
236-
renderedPathname = new URL(renderedUrlParts.join('/'), 'http://localhost')
237-
.pathname
238-
}
239-
240224
return {
241-
flightData: normalizeFlightData(response.f, renderedPathname),
225+
flightData: normalizeFlightData(response.f),
242226
canonicalUrl: canonicalUrl,
243227
couldBeIntercepted: interception,
244228
prerendered: response.S,

packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ import {
5656
omitUnusedArgs,
5757
} from '../../../../shared/lib/server-reference-info'
5858
import { revalidateEntireCache } from '../../segment-cache'
59-
import { getRenderedPathname } from '../../../route-params'
6059

6160
const createFromFetch =
6261
createFromFetchBrowser as (typeof import('react-server-dom-webpack/client.browser'))['createFromFetch']
@@ -183,24 +182,9 @@ async function fetchServerAction(
183182
{ callServer, findSourceMapURL, temporaryReferences }
184183
)
185184

186-
let renderedPathname
187-
if (process.env.__NEXT_CLIENT_SEGMENT_CACHE) {
188-
// Read the URL from the response object.
189-
renderedPathname = getRenderedPathname(res)
190-
} else {
191-
// Before Segment Cache is enabled, we should not rely on the new
192-
// rewrite headers (x-rewritten-path, x-rewritten-query) because that
193-
// is a breaking change. Read the URL from the response body.
194-
const canonicalUrlParts = response.c
195-
renderedPathname = new URL(
196-
canonicalUrlParts.join('/'),
197-
'http://localhost'
198-
).pathname
199-
}
200-
201185
// An internal redirect can send an RSC response, but does not have a useful `actionResult`.
202186
actionResult = redirectLocation ? undefined : response.a
203-
actionFlightData = normalizeFlightData(response.f, renderedPathname)
187+
actionFlightData = normalizeFlightData(response.f)
204188
} else {
205189
// An external redirect doesn't contain RSC data.
206190
actionResult = undefined

packages/next/src/client/components/segment-cache-impl/cache.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import type {
4646
import {
4747
doesStaticSegmentAppearInURL,
4848
getCacheKeyForDynamicParam,
49+
getParamValueFromCacheKey,
4950
getRenderedPathname,
5051
getRenderedSearch,
5152
parseDynamicParamFromURLPart,
@@ -975,12 +976,7 @@ function convertTreePrefetchToRouteTree(
975976
value: childParamValue,
976977
type: childParamType,
977978
}
978-
childSegment = [
979-
childParamName,
980-
childParamKey,
981-
childParamType,
982-
childParamValue,
983-
]
979+
childSegment = [childParamName, childParamKey, childParamType]
984980
childDoesAppearInURL = true
985981
} else {
986982
childSegment = childParamName
@@ -1082,7 +1078,9 @@ function convertFlightRouterStateToRouteTree(
10821078
let segment: FlightRouterStateSegment
10831079
let param: RouteParam | null = null
10841080
if (Array.isArray(originalSegment)) {
1085-
const paramValue = originalSegment[3]
1081+
const paramCacheKey = originalSegment[1]
1082+
const paramType = originalSegment[2]
1083+
const paramValue = getParamValueFromCacheKey(paramCacheKey, paramType)
10861084
param = {
10871085
name: originalSegment[0],
10881086
value: paramValue === undefined ? null : paramValue,
@@ -1647,12 +1645,8 @@ function writeDynamicTreeResponseIntoCache(
16471645
// Get the URL that was used to render the target page. This may be different
16481646
// from the URL in the request URL, if the page was rewritten.
16491647
const renderedSearch = getRenderedSearch(response)
1650-
const renderedPathname = getRenderedPathname(response)
16511648

1652-
const normalizedFlightDataResult = normalizeFlightData(
1653-
serverData.f,
1654-
renderedPathname
1655-
)
1649+
const normalizedFlightDataResult = normalizeFlightData(serverData.f)
16561650
if (
16571651
// A string result means navigating to this route will result in an
16581652
// MPA navigation.
@@ -1759,11 +1753,7 @@ function writeDynamicRenderResponseIntoCache(
17591753
return null
17601754
}
17611755

1762-
// Get the URL that was used to render the target page. This may be different
1763-
// from the URL in the request URL, if the page was rewritten.
1764-
const renderedPathname = getRenderedPathname(response)
1765-
1766-
const flightDatas = normalizeFlightData(serverData.f, renderedPathname)
1756+
const flightDatas = normalizeFlightData(serverData.f)
17671757
if (typeof flightDatas === 'string') {
17681758
// This means navigating to this route will result in an MPA navigation.
17691759
// TODO: We should cache this, too, so that the MPA navigation is immediate.

packages/next/src/client/flight-data-helpers.ts

Lines changed: 3 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {
22
CacheNodeSeedData,
3-
DynamicParamTypesShort,
43
FlightData,
54
FlightDataPath,
65
FlightRouterState,
@@ -9,10 +8,6 @@ import type {
98
} from '../server/app-render/types'
109
import type { HeadData } from '../shared/lib/app-router-context.shared-runtime'
1110
import { PAGE_SEGMENT_KEY } from '../shared/lib/segment'
12-
import {
13-
doesStaticSegmentAppearInURL,
14-
parseDynamicParamFromURLPart,
15-
} from './route-params'
1611

1712
export type NormalizedFlightData = {
1813
/**
@@ -36,8 +31,7 @@ export type NormalizedFlightData = {
3631
// we're currently exporting it so we can use it directly. This should be fixed as part of the unification of
3732
// the different ways we express `FlightSegmentPath`.
3833
export function getFlightDataPartsFromPath(
39-
flightDataPath: FlightDataPath,
40-
renderedPathname: string
34+
flightDataPath: FlightDataPath
4135
): NormalizedFlightData {
4236
// Pick the last 4 items from the `FlightDataPath` to get the [tree, seedData, viewport, isHeadPartial].
4337
const flightDataPathLength = 4
@@ -47,8 +41,6 @@ export function getFlightDataPartsFromPath(
4741
// The `FlightSegmentPath` is everything except the last three items. For a root render, it won't be present.
4842
const segmentPath = flightDataPath.slice(0, -flightDataPathLength)
4943

50-
fillTreeWithParamValues(renderedPathname, segmentPath, tree)
51-
5244
return {
5345
// TODO: Unify these two segment path helpers. We are inconsistently pushing an empty segment ("")
5446
// to the start of the segment path in some places which makes it hard to use solely the segment path.
@@ -75,8 +67,7 @@ export function getNextFlightSegmentPath(
7567
}
7668

7769
export function normalizeFlightData(
78-
flightData: FlightData,
79-
renderedPathname: string
70+
flightData: FlightData
8071
): NormalizedFlightData[] | string {
8172
// FlightData can be a string when the server didn't respond with a proper flight response,
8273
// or when a redirect happens, to signal to the client that it needs to perform an MPA navigation.
@@ -85,7 +76,7 @@ export function normalizeFlightData(
8576
}
8677

8778
return flightData.map((flightDataPath) =>
88-
getFlightDataPartsFromPath(flightDataPath, renderedPathname)
79+
getFlightDataPartsFromPath(flightDataPath)
8980
)
9081
}
9182

@@ -180,93 +171,3 @@ function shouldPreserveRefreshMarker(
180171
): boolean {
181172
return Boolean(refreshMarker && refreshMarker !== 'refresh')
182173
}
183-
184-
function fillTreeWithParamValues(
185-
renderedPathname: string,
186-
segmentPath: FlightSegmentPath,
187-
flightRouterState: FlightRouterState
188-
): void {
189-
// Traverse the FlightRouterState and fill in the param values using the
190-
// rendered pathname.
191-
192-
// Remove trailing and leading slashes, then split the pathname into parts.
193-
// These will be assigned as params as we traverse the tree.
194-
const pathnameParts = renderedPathname.split('/').filter((p) => p !== '')
195-
196-
let pathnamePartsIndex = 0
197-
198-
// segmentPath represents the parent path of subtree. It's a repeating pattern
199-
// of parallel route key and segment:
200-
//
201-
// [string, Segment, string, Segment, string, Segment, ...]
202-
//
203-
// Iterate through the path and skip over the corresponding pathname parts.
204-
for (let i = 0; i < segmentPath.length; i += 2) {
205-
const segment: Segment = segmentPath[i + 1]
206-
if (Array.isArray(segment) || doesStaticSegmentAppearInURL(segment)) {
207-
// This segment appears in the URL, so we need to skip over this part
208-
// of the pathname
209-
pathnamePartsIndex++
210-
}
211-
}
212-
213-
fillTreeWithParamValuesImpl(
214-
renderedPathname,
215-
flightRouterState,
216-
pathnameParts,
217-
pathnamePartsIndex
218-
)
219-
}
220-
221-
function fillTreeWithParamValuesImpl(
222-
renderedPathname: string,
223-
flightRouterState: FlightRouterState,
224-
pathnameParts: Array<string>,
225-
pathnamePartsIndex: number
226-
): void {
227-
const segment = flightRouterState[0]
228-
229-
let doesAppearInURL: boolean
230-
if (Array.isArray(segment)) {
231-
doesAppearInURL = true
232-
233-
// This segment is parameterized. Get the param from the pathname.
234-
const paramType = segment[2] as DynamicParamTypesShort
235-
const paramValue = parseDynamicParamFromURLPart(
236-
paramType,
237-
pathnameParts,
238-
pathnamePartsIndex
239-
)
240-
241-
// Insert the param value into the segment.
242-
// TODO: Eventually this is the value that will be passed to client
243-
// components that render this param.
244-
segment[3] = paramValue
245-
246-
// Assign a cache key to the segment, based on the param value. In the
247-
// pre-Segment Cache implementation, the server computes this and sends it
248-
// in the body of the response. In the Segment Cache implementation, the
249-
// server sends an empty string and we fill it in here.
250-
// TODO: This will land in a follow up PR.
251-
// const segmentCacheKey = getCacheKeyForDynamicParam(paramValue)
252-
// segment[1] = segmentCacheKey
253-
} else {
254-
doesAppearInURL = doesStaticSegmentAppearInURL(segment)
255-
}
256-
257-
// Only increment the index if the segment appears in the URL. If it's a
258-
// "virtual" segment, like a route group, it remains the same.
259-
const childPathnamePartsIndex = doesAppearInURL
260-
? pathnamePartsIndex + 1
261-
: pathnamePartsIndex
262-
263-
const parallelRoutes = flightRouterState[1]
264-
for (const parallelRouteKey in parallelRoutes) {
265-
fillTreeWithParamValuesImpl(
266-
renderedPathname,
267-
parallelRoutes[parallelRouteKey],
268-
pathnameParts,
269-
childPathnamePartsIndex
270-
)
271-
}
272-
}

packages/next/src/client/route-params.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,22 @@ export function urlToUrlWithoutFlightMarker(url: URL): URL {
159159
}
160160
return urlWithoutFlightParameters
161161
}
162+
163+
export function getParamValueFromCacheKey(
164+
paramCacheKey: string,
165+
paramType: DynamicParamTypesShort
166+
) {
167+
// Turn the cache key string sent by the server (as part of FlightRouterState)
168+
// into a value that can be passed to `useParams` and client components.
169+
const isCatchAll = paramType === 'c' || paramType === 'oc'
170+
if (isCatchAll) {
171+
// Catch-all param keys are a concatenation of the path segments.
172+
// See equivalent logic in `getSelectedParams`.
173+
// TODO: We should just pass the array directly, rather than concatenate
174+
// it to a string and then split it back to an array. It needs to be an
175+
// array in some places, like when passing a key React, but we can convert
176+
// it at runtime in those places.
177+
return paramCacheKey.split('/')
178+
}
179+
return paramCacheKey
180+
}

packages/next/src/server/app-render/app-render.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,14 +505,12 @@ async function generateDynamicRSCPayload(
505505
a: options.actionResult,
506506
f: flightData,
507507
b: ctx.sharedContext.buildId,
508-
c: prepareInitialCanonicalUrl(url),
509508
}
510509
}
511510

512511
// Otherwise, it's a regular RSC response.
513512
return {
514513
b: ctx.sharedContext.buildId,
515-
c: prepareInitialCanonicalUrl(url),
516514
f: flightData,
517515
S: workStore.isStaticGeneration,
518516
}

0 commit comments

Comments
 (0)