diff --git a/packages/next/src/client/components/app-router-headers.ts b/packages/next/src/client/components/app-router-headers.ts index 0ef9942f6b965..f8d042317f049 100644 --- a/packages/next/src/client/components/app-router-headers.ts +++ b/packages/next/src/client/components/app-router-headers.ts @@ -7,7 +7,7 @@ export const NEXT_URL = 'Next-Url' as const export const FETCH_CACHE_HEADER = 'x-vercel-sc-headers' as const export const RSC_CONTENT_TYPE_HEADER = 'text/x-component' as const export const RSC_VARY_HEADER = - `${RSC}, ${NEXT_ROUTER_STATE_TREE}, ${NEXT_ROUTER_PREFETCH}` as const + `${RSC}, ${NEXT_ROUTER_STATE_TREE}, ${NEXT_ROUTER_PREFETCH}, ${NEXT_URL}` as const export const FLIGHT_PARAMETERS = [ [RSC], diff --git a/packages/next/src/client/components/router-reducer/fetch-server-response.ts b/packages/next/src/client/components/router-reducer/fetch-server-response.ts index 46602ece29b72..689d27df7798f 100644 --- a/packages/next/src/client/components/router-reducer/fetch-server-response.ts +++ b/packages/next/src/client/components/router-reducer/fetch-server-response.ts @@ -72,6 +72,7 @@ export async function fetchServerResponse( [ headers[NEXT_ROUTER_PREFETCH] || '0', headers[NEXT_ROUTER_STATE_TREE], + headers[NEXT_URL], ].join(',') ) diff --git a/test/e2e/app-dir/app-prefetch/app/dashboard/page.js b/test/e2e/app-dir/app-prefetch/app/dashboard/page.js index 4a56f8e04184c..8ad248aa42420 100644 --- a/test/e2e/app-dir/app-prefetch/app/dashboard/page.js +++ b/test/e2e/app-dir/app-prefetch/app/dashboard/page.js @@ -1,3 +1,5 @@ +import Link from 'next/link' + export const revalidate = 0 async function getData() { @@ -12,6 +14,9 @@ export default async function DashboardPage(props) { return ( <>

{message}

+ + To Static Page + ) } diff --git a/test/e2e/app-dir/app-prefetch/prefetching.test.ts b/test/e2e/app-dir/app-prefetch/prefetching.test.ts index 189d27acc6f64..71bdc82549408 100644 --- a/test/e2e/app-dir/app-prefetch/prefetching.test.ts +++ b/test/e2e/app-dir/app-prefetch/prefetching.test.ts @@ -157,6 +157,43 @@ createNextDescribe( ).toBe(1) }) + it('should calculate `_rsc` query based on `Next-Url`', async () => { + const browser = await next.browser('/404', browserConfigWithFixedTime) + let staticPageRequests: string[] = [] + + browser.on('request', (req) => { + const url = new URL(req.url()) + if (url.toString().includes(`/static-page?${NEXT_RSC_UNION_QUERY}=`)) { + staticPageRequests.push(`${url.pathname}${url.search}`) + } + }) + await browser.eval('location.href = "/"') + await browser.eval( + `window.nd.router.prefetch("/static-page", {kind: "auto"})` + ) + await check(() => { + return staticPageRequests.length === 1 + ? 'success' + : JSON.stringify(staticPageRequests) + }, 'success') + + // Unable to clear router cache so mpa navigation + await browser.eval('location.href = "/dashboard"') + await browser.eval( + `window.nd.router.prefetch("/static-page", {kind: "auto"})` + ) + await check(() => { + return staticPageRequests.length === 2 + ? 'success' + : JSON.stringify(staticPageRequests) + }, 'success') + + expect(staticPageRequests[0]).toMatch('/static-page?_rsc=') + expect(staticPageRequests[1]).toMatch('/static-page?_rsc=') + // `_rsc` does not match because it depends on the `Next-Url` + expect(staticPageRequests[0]).not.toBe(staticPageRequests[1]) + }) + it('should not prefetch for a bot user agent', async () => { const browser = await next.browser('/404') let requests: string[] = [] diff --git a/test/e2e/app-dir/app/index.test.ts b/test/e2e/app-dir/app/index.test.ts index 831bc3dedd420..66e77aad46ff6 100644 --- a/test/e2e/app-dir/app/index.test.ts +++ b/test/e2e/app-dir/app/index.test.ts @@ -256,8 +256,8 @@ createNextDescribe( expect(res.headers.get('x-edge-runtime')).toBe('1') expect(res.headers.get('vary')).toBe( isNextDeploy - ? 'RSC, Next-Router-State-Tree, Next-Router-Prefetch' - : 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Accept-Encoding' + ? 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url' + : 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url, Accept-Encoding' ) }) @@ -269,8 +269,8 @@ createNextDescribe( }) expect(res.headers.get('vary')).toBe( isNextDeploy - ? 'RSC, Next-Router-State-Tree, Next-Router-Prefetch' - : 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Accept-Encoding' + ? 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url' + : 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url, Accept-Encoding' ) }) diff --git a/test/integration/custom-routes/test/index.test.js b/test/integration/custom-routes/test/index.test.js index eda2ebfc65d66..0a28aa5f21698 100644 --- a/test/integration/custom-routes/test/index.test.js +++ b/test/integration/custom-routes/test/index.test.js @@ -2658,7 +2658,8 @@ const runTests = (isDev = false, isTurbo = false) => { rsc: { header: 'RSC', contentTypeHeader: 'text/x-component', - varyHeader: 'RSC, Next-Router-State-Tree, Next-Router-Prefetch', + varyHeader: + 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url', }, }) }) diff --git a/test/integration/dynamic-routing/test/index.test.js b/test/integration/dynamic-routing/test/index.test.js index 2699e64d2bc6e..417e5317b36db 100644 --- a/test/integration/dynamic-routing/test/index.test.js +++ b/test/integration/dynamic-routing/test/index.test.js @@ -1462,7 +1462,8 @@ function runTests({ dev }) { rsc: { header: 'RSC', contentTypeHeader: 'text/x-component', - varyHeader: 'RSC, Next-Router-State-Tree, Next-Router-Prefetch', + varyHeader: + 'RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url', }, }) })