Skip to content

Commit

Permalink
refactor FetchServerResponse shape
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner committed Jul 17, 2024
1 parent 50cc926 commit 5f5a368
Show file tree
Hide file tree
Showing 12 changed files with 47 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function createInitialRouterState({
createPrefetchCacheEntryForInitialLoad({
url,
kind: PrefetchKind.AUTO,
data: [initialFlightData, undefined, couldBeIntercepted],
data: { f: initialFlightData, c: undefined, i: !!couldBeIntercepted },
tree: initialState.tree,
prefetchCache: initialState.prefetchCache,
nextUrl: initialState.nextUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ const { createFromFetch } = (

import type {
FlightRouterState,
FlightData,
NavigationFlightResponse,
FetchServerResponseResult,
} from '../../../server/app-render/types'
import {
NEXT_ROUTER_PREFETCH_HEADER,
Expand All @@ -37,12 +37,6 @@ export interface FetchServerResponseOptions {
readonly isHmrRefresh?: boolean
}

export type FetchServerResponseResult = [
flightData: FlightData,
canonicalUrlOverride: URL | undefined,
intercepted?: boolean,
]

function urlToUrlWithoutFlightMarker(url: string): URL {
const urlWithoutFlightParameters = new URL(url, location.origin)
urlWithoutFlightParameters.searchParams.delete(NEXT_RSC_UNION_QUERY)
Expand All @@ -61,7 +55,11 @@ function urlToUrlWithoutFlightMarker(url: string): URL {
}

function doMpaNavigation(url: string): FetchServerResponseResult {
return [urlToUrlWithoutFlightMarker(url).toString(), undefined, false]
return {
f: urlToUrlWithoutFlightMarker(url).toString(),
c: undefined,
i: false,
}
}

/**
Expand Down Expand Up @@ -191,7 +189,11 @@ export async function fetchServerResponse(
return doMpaNavigation(res.url)
}

return [response.f, canonicalUrl, interception]
return {
f: response.f,
c: canonicalUrl,
i: interception,
}
} catch (err) {
console.error(
`Failed to fetch RSC payload for ${url}. Falling back to browser navigation.`,
Expand All @@ -200,6 +202,10 @@ export async function fetchServerResponse(
// If fetch fails handle it like a mpa navigation
// TODO-APP: Add a test for the case where a CORS request fails, e.g. external url redirect coming from the response.
// See https://github.com/vercel/next.js/issues/43605#issuecomment-1451617521 for a reproduction.
return [url.toString(), undefined, false]
return {
f: url.toString(),
c: undefined,
i: false,
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
FlightRouterState,
FlightSegmentPath,
Segment,
FetchServerResponseResult,
} from '../../../server/app-render/types'
import type {
CacheNode,
Expand All @@ -15,7 +16,6 @@ import {
} from '../../../shared/lib/segment'
import { matchSegment } from '../match-segments'
import { createRouterCacheKey } from './create-router-cache-key'
import type { FetchServerResponseResult } from './fetch-server-response'

// This is yet another tree type that is used to track pending promises that
// need to be fulfilled once the dynamic data is received. The terminal nodes of
Expand Down Expand Up @@ -353,8 +353,7 @@ export function listenForDynamicRequest(
responsePromise: Promise<FetchServerResponseResult>
) {
responsePromise.then(
(response: FetchServerResponseResult) => {
const flightData = response[0]
({ f: flightData }: FetchServerResponseResult) => {
for (const flightDataPath of flightData) {
const segmentPath = flightDataPath.slice(0, -3)
const serverRouterState = flightDataPath[flightDataPath.length - 3]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { createHrefFromUrl } from './create-href-from-url'
import {
fetchServerResponse,
type FetchServerResponseResult,
} from './fetch-server-response'
import { fetchServerResponse } from './fetch-server-response'
import {
PrefetchCacheEntryStatus,
type PrefetchCacheEntry,
PrefetchKind,
type ReadonlyReducerState,
} from './router-reducer-types'
import { prefetchQueue } from './reducers/prefetch-reducer'
import type { FetchServerResponseResult } from '../../../server/app-render/types'

/**
* Creates a cache key for the router prefetch cache
Expand Down Expand Up @@ -152,9 +150,8 @@ export function createPrefetchCacheEntryForInitialLoad({
kind: PrefetchKind
data: FetchServerResponseResult
}) {
const [, , intercept] = data
// if the prefetch corresponds with an interception route, we use the nextUrl to prefix the cache key
const prefetchCacheKey = intercept
const prefetchCacheKey = data.i
? createPrefetchCacheKey(url, nextUrl)
: createPrefetchCacheKey(url)

Expand Down Expand Up @@ -204,8 +201,7 @@ function createLazyPrefetchEntry({
// TODO: `fetchServerResponse` should be more tighly coupled to these prefetch cache operations
// to avoid drift between this cache key prefixing logic
// (which is currently directly influenced by the server response)
const [, , intercepted] = prefetchResponse
if (intercepted) {
if (prefetchResponse.i) {
prefixExistingPrefetchCacheEntry({ url, nextUrl, prefetchCache })
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function hmrRefreshReducerImpl(
})

return cache.lazyData.then(
([flightData, canonicalUrlOverride]) => {
({ f: flightData, c: canonicalUrlOverride }) => {
// Handle case when navigating to page in `pages` from `app`
if (typeof flightData === 'string') {
return handleExternalUrl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ function navigateReducer_noPPR(
prefetchQueue.bump(data)

return data.then(
([flightData, canonicalUrlOverride]) => {
({ f: flightData, c: canonicalUrlOverride }) => {
let isFirstRead = false
// we only want to mark this once
if (!prefetchValues.lastUsedTime) {
Expand Down Expand Up @@ -324,7 +324,7 @@ function navigateReducer_PPR(
prefetchQueue.bump(data)

return data.then(
([flightData, canonicalUrlOverride]) => {
({ f: flightData, c: canonicalUrlOverride }) => {
let isFirstRead = false
// we only want to mark this once
if (!prefetchValues.lastUsedTime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function refreshReducer(
})

return cache.lazyData.then(
async ([flightData, canonicalUrlOverride]) => {
async ({ f: flightData, c: canonicalUrlOverride }) => {
// Handle case when navigating to page in `pages` from `app`
if (typeof flightData === 'string') {
return handleExternalUrl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ export function serverPatchReducer(
state: ReadonlyReducerState,
action: ServerPatchAction
): ReducerState {
const { serverResponse } = action
const [flightData, overrideCanonicalUrl] = serverResponse
const {
serverResponse: { f: flightData, c: canonicalUrlOverride },
} = action

const mutable: Mutable = {}

Expand Down Expand Up @@ -64,8 +65,8 @@ export function serverPatchReducer(
)
}

const canonicalUrlOverrideHref = overrideCanonicalUrl
? createHrefFromUrl(overrideCanonicalUrl)
const canonicalUrlOverrideHref = canonicalUrlOverride
? createHrefFromUrl(canonicalUrlOverride)
: undefined

if (canonicalUrlOverrideHref) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ async function refreshInactiveParallelSegmentsImpl({
nextUrl: includeNextUrl ? state.nextUrl : null,
buildId: state.buildId,
}
).then((fetchResponse) => {
const flightData = fetchResponse[0]
).then(({ f: flightData }) => {
if (typeof flightData !== 'string') {
for (const flightDataPath of flightData) {
// we only pass the new cache as this function is called after clearing the router cache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { CacheNode } from '../../../shared/lib/app-router-context.shared-ru
import type {
FlightRouterState,
FlightSegmentPath,
FetchServerResponseResult,
} from '../../../server/app-render/types'
import type { FetchServerResponseResult } from './fetch-server-response'

export const ACTION_REFRESH = 'refresh'
export const ACTION_NAVIGATE = 'navigate'
Expand Down
9 changes: 9 additions & 0 deletions packages/next/src/server/app-render/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,15 @@ export type ActionFlightResponse = {
f: FlightData | null
}

export type FetchServerResponseResult = {
/** flightData */
f: FlightData
/** canonicalUrl */
c: URL | undefined
/** couldBeIntercepted */
i: boolean
}

export type RSCPayload =
| InitialRSCPayload
| NavigationFlightResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import type {
PrefetchKind,
RouterChangeByServerResponse,
} from '../../client/components/router-reducer/router-reducer-types'
import type { FetchServerResponseResult } from '../../client/components/router-reducer/fetch-server-response'
import type { FlightRouterState } from '../../server/app-render/types'
import type {
FlightRouterState,
FetchServerResponseResult,
} from '../../server/app-render/types'
import React from 'react'

export type ChildSegmentMap = Map<string, CacheNode>
Expand Down

0 comments on commit 5f5a368

Please sign in to comment.