diff --git a/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs index fdb7dc3193efe..dd086933bb530 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs @@ -81,7 +81,6 @@ pub async fn get_app_page_entry( indexmap! { "VAR_DEFINITION_PAGE" => page.to_string(), "VAR_DEFINITION_PATHNAME" => pathname.clone(), - "VAR_ORIGINAL_PATHNAME" => original_name.clone(), // TODO(alexkirsz) Support custom global error. "VAR_MODULE_GLOBAL_ERROR" => "next/dist/client/components/error-boundary".to_string(), }, diff --git a/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs index 3031fbab4cafc..0971d581fe68a 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs @@ -84,7 +84,6 @@ pub async fn get_app_route_entry( "VAR_DEFINITION_FILENAME" => path.file_stem().await?.as_ref().unwrap().clone(), // TODO(alexkirsz) Is this necessary? "VAR_DEFINITION_BUNDLE_PATH" => "".to_string(), - "VAR_ORIGINAL_PATHNAME" => original_name.clone(), "VAR_RESOLVED_PAGE_PATH" => path.to_string().await?.clone_value(), "VAR_USERLAND" => INNER.to_string(), }, diff --git a/packages/next/src/build/templates/app-page.ts b/packages/next/src/build/templates/app-page.ts index 9879f48eda27c..fb8bb173d33d2 100644 --- a/packages/next/src/build/templates/app-page.ts +++ b/packages/next/src/build/templates/app-page.ts @@ -29,7 +29,6 @@ declare const __next_app_load_chunk__: any // INJECT:__next_app_require__ // INJECT:__next_app_load_chunk__ -export const originalPathname = 'VAR_ORIGINAL_PATHNAME' export const __next_app__ = { require: __next_app_require__, loadChunk: __next_app_load_chunk__, diff --git a/packages/next/src/build/templates/app-route.ts b/packages/next/src/build/templates/app-route.ts index 4aaea88b9a4d9..099fc7d5fb779 100644 --- a/packages/next/src/build/templates/app-route.ts +++ b/packages/next/src/build/templates/app-route.ts @@ -35,8 +35,6 @@ const routeModule = new AppRouteRouteModule({ const { requestAsyncStorage, staticGenerationAsyncStorage, serverHooks } = routeModule -const originalPathname = 'VAR_ORIGINAL_PATHNAME' - function patchFetch() { return _patchFetch({ serverHooks, staticGenerationAsyncStorage }) } @@ -46,6 +44,5 @@ export { requestAsyncStorage, staticGenerationAsyncStorage, serverHooks, - originalPathname, patchFetch, } diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index a422c3bf046c0..7999bd21438f2 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -1385,9 +1385,8 @@ export async function buildAppStaticPaths({ return StaticGenerationAsyncStorageWrapper.wrap( ComponentMod.staticGenerationAsyncStorage, { - url: { pathname: page }, + page, renderOpts: { - originalPathname: page, incrementalCache, supportsDynamicHTML: true, isRevalidate: false, diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index b2f4d6279adae..fdfb3ebafe509 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -145,7 +145,6 @@ async function createAppRouteCode({ VAR_DEFINITION_FILENAME: filename, VAR_DEFINITION_BUNDLE_PATH: bundlePath, VAR_RESOLVED_PAGE_PATH: resolvedPagePath, - VAR_ORIGINAL_PATHNAME: page, }, { nextConfigOutput: JSON.stringify(nextConfigOutput), @@ -773,7 +772,6 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { VAR_DEFINITION_PAGE: page, VAR_DEFINITION_PATHNAME: pathname, VAR_MODULE_GLOBAL_ERROR: treeCodeResult.globalError, - VAR_ORIGINAL_PATHNAME: page, }, { tree: treeCodeResult.treeCode, diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.external.ts index 6ed246b8497a8..f426f7ff8f52d 100644 --- a/packages/next/src/client/components/static-generation-async-storage.external.ts +++ b/packages/next/src/client/components/static-generation-async-storage.external.ts @@ -12,12 +12,27 @@ import { staticGenerationAsyncStorage } from './static-generation-async-storage- export interface StaticGenerationStore { readonly isStaticGeneration: boolean - readonly pagePath?: string + /** + * The page that is being rendered. This is the path to the page file. + */ + readonly page: string + /** * The URL of the request. This only specifies the pathname and the search - * part of the URL. The other parts aren't accepted so they shouldn't be used. + * part of the URL. */ - readonly url: { readonly pathname: string; readonly search: string } + readonly url?: { + /** + * The pathname of the requested URL. + */ + readonly pathname: string + + /** + * The search part of the requested URL. If the request did not provide a + * search part, this will be undefined. + */ + readonly search?: string + } readonly incrementalCache?: IncrementalCache readonly isOnDemandRevalidate?: boolean readonly isPrerendering?: boolean diff --git a/packages/next/src/export/routes/app-route.ts b/packages/next/src/export/routes/app-route.ts index 189b307c28fd0..01050f407b9ee 100644 --- a/packages/next/src/export/routes/app-route.ts +++ b/packages/next/src/export/routes/app-route.ts @@ -64,7 +64,6 @@ export async function exportAppRoute( notFoundRoutes: [], }, renderOpts: { - originalPathname: page, nextExport: true, supportsDynamicHTML: false, incrementalCache, diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index 7f973ffae3764..417909c9acc48 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -269,7 +269,6 @@ async function exportPageImpl( fontManifest: optimizeFonts ? requireFontManifest(distDir) : undefined, locale, supportsDynamicHTML: false, - originalPathname: page, experimental: { ...input.renderOpts.experimental, isRoutePPREnabled, diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index d812044245594..d6ef01b98d78a 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -312,7 +312,7 @@ async function generateFlight( }, getDynamicParamFromSegment, appUsingSizeAdjustment, - staticGenerationStore: { url }, + staticGenerationStore: { page, url }, query, requestId, flightRouterState, @@ -321,7 +321,7 @@ async function generateFlight( if (!options?.skipFlight) { const [MetadataTree, MetadataOutlet] = createMetadataComponents({ tree: loaderTree, - pathname: url.pathname, + pathname: url?.pathname ?? page, trailingSlash: ctx.renderOpts.trailingSlash, query, getDynamicParamFromSegment, @@ -434,7 +434,7 @@ async function ReactServerApp({ tree, ctx, asNotFound }: ReactServerAppProps) { GlobalError, createDynamicallyTrackedSearchParams, }, - staticGenerationStore: { url }, + staticGenerationStore: { page, url }, } = ctx const initialTree = createFlightRouterStateFromLoaderTree( tree, @@ -445,7 +445,7 @@ async function ReactServerApp({ tree, ctx, asNotFound }: ReactServerAppProps) { const [MetadataTree, MetadataOutlet] = createMetadataComponents({ tree, errorType: asNotFound ? 'not-found' : undefined, - pathname: url.pathname, + pathname: url?.pathname ?? page, trailingSlash: ctx.renderOpts.trailingSlash, query, getDynamicParamFromSegment: getDynamicParamFromSegment, @@ -481,7 +481,7 @@ async function ReactServerApp({ tree, ctx, asNotFound }: ReactServerAppProps) { , loadingData, ], diff --git a/packages/next/src/server/app-render/dynamic-rendering.ts b/packages/next/src/server/app-render/dynamic-rendering.ts index 7a247bed95120..76781fd39f64d 100644 --- a/packages/next/src/server/app-render/dynamic-rendering.ts +++ b/packages/next/src/server/app-render/dynamic-rendering.ts @@ -75,7 +75,8 @@ export function markCurrentScopeAsDynamic( store: StaticGenerationStore, expression: string ): void { - const { pathname } = store.url + const { page, url } = store + const pathname = url?.pathname ?? page if (store.isUnstableCacheCallback) { // inside cache scopes marking a scope as dynamic has no effect because the outer cache scope // creates a cache boundary. This is subtly different from reading a dynamic data source which is @@ -122,7 +123,8 @@ export function trackDynamicDataAccessed( store: StaticGenerationStore, expression: string ): void { - const { pathname } = store.url + const { page, url } = store + const pathname = url?.pathname ?? page if (store.isUnstableCacheCallback) { throw new Error( `Route ${pathname} used "${expression}" inside a function cached with "unstable_cache(...)". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "${expression}" outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache` @@ -183,7 +185,11 @@ export function trackDynamicFetch( // don't need to postpone. if (!store.prerenderState || store.isUnstableCacheCallback) return - postponeWithTracking(store.prerenderState, expression, store.url.pathname) + postponeWithTracking( + store.prerenderState, + expression, + store.url?.pathname ?? store.page + ) } function postponeWithTracking( diff --git a/packages/next/src/server/app-render/types.ts b/packages/next/src/server/app-render/types.ts index b1287d261049a..88b74f6ccc383 100644 --- a/packages/next/src/server/app-render/types.ts +++ b/packages/next/src/server/app-render/types.ts @@ -141,7 +141,6 @@ export interface RenderOptsPartial { nextExport?: boolean nextConfigOutput?: 'standalone' | 'export' appDirDevErrorLogger?: (err: any) => Promise - originalPathname?: string isDraftMode?: boolean deploymentId?: string onUpdateCookies?: (cookies: string[]) => void diff --git a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts index 84defb92d333d..1d28c20d21736 100644 --- a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts @@ -8,11 +8,27 @@ import { createPrerenderState } from '../../server/app-render/dynamic-rendering' import type { FetchMetric } from '../base-http' export type StaticGenerationContext = { + /** + * The page that is being rendered. This relates to the path to the page file. + */ + page: string + /** * The URL of the request. This only specifies the pathname and the search - * part of the URL. The other parts aren't accepted so they shouldn't be used. + * part of the URL. */ - url: { pathname: string; search?: string } + url?: { + /** + * The pathname of the requested URL. + */ + pathname: string + + /** + * The search part of the requested URL. If the request did not provide a + * search part, this will be an empty string. + */ + search?: string + } requestEndedState?: { ended?: boolean } renderOpts: { incrementalCache?: IncrementalCache @@ -40,7 +56,6 @@ export type StaticGenerationContext = { // Pull some properties from RenderOptsPartial so that the docs are also // mirrored. RenderOptsPartial, - | 'originalPathname' | 'supportsDynamicHTML' | 'isRevalidate' | 'nextExport' @@ -55,7 +70,7 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper< > = { wrap( storage: AsyncLocalStorage, - { url, renderOpts, requestEndedState }: StaticGenerationContext, + { page, url, renderOpts, requestEndedState }: StaticGenerationContext, callback: (store: StaticGenerationStore) => Result ): Result { /** @@ -87,14 +102,13 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper< const store: StaticGenerationStore = { isStaticGeneration, + page, // Rather than just using the whole `url` here, we pull the parts we want // to ensure we don't use parts of the URL that we shouldn't. This also // lets us avoid requiring an empty string for `search` in the type. - url: { - pathname: url.pathname, - search: url.search ?? '', - }, - pagePath: renderOpts.originalPathname, + url: url + ? { pathname: url.pathname, search: url.search ?? '' } + : undefined, incrementalCache: // we fallback to a global incremental cache for edge-runtime locally // so that it can access the fs cache without mocks diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index fb8da83c9824b..9d82a5f25734f 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -2281,7 +2281,6 @@ export default abstract class Server< // it is not a dynamic RSC request then it is a revalidation // request. isRevalidate: isSSG && !postponed && !isDynamicRSCRequest, - originalPathname: components.ComponentMod.originalPathname, serverActions: this.nextConfig.experimental.serverActions, } : {}), @@ -2344,7 +2343,6 @@ export default abstract class Server< params: opts.params, prerenderManifest, renderOpts: { - originalPathname: components.ComponentMod.originalPathname, supportsDynamicHTML, incrementalCache, isRevalidate: isSSG, diff --git a/packages/next/src/server/future/route-modules/app-route/module.ts b/packages/next/src/server/future/route-modules/app-route/module.ts index cfb37d03a7ce1..9d0d84f0f97c4 100644 --- a/packages/next/src/server/future/route-modules/app-route/module.ts +++ b/packages/next/src/server/future/route-modules/app-route/module.ts @@ -257,6 +257,7 @@ export class AppRouteRouteModule extends RouteModule< // Get the context for the static generation. const staticGenerationContext: StaticGenerationContext = { + page: this.definition.page, url: rawRequest.nextUrl, renderOpts: context.renderOpts, } diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 20bfea528c97b..660096bbbcd96 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -129,17 +129,14 @@ const getDerivedTags = (pathname: string): string[] => { export function addImplicitTags(staticGenerationStore: StaticGenerationStore) { const newTags: string[] = [] - const { - pagePath, - url: { pathname }, - } = staticGenerationStore + const { page, url } = staticGenerationStore if (!Array.isArray(staticGenerationStore.tags)) { staticGenerationStore.tags = [] } - if (pagePath) { - const derivedTags = getDerivedTags(pagePath) + if (page) { + const derivedTags = getDerivedTags(page) for (let tag of derivedTags) { tag = `${NEXT_CACHE_IMPLICIT_TAG_ID}${tag}` @@ -150,6 +147,8 @@ export function addImplicitTags(staticGenerationStore: StaticGenerationStore) { } } + // TODO: verify that this is the correct behavior + const pathname = url?.pathname ?? page if (pathname) { const tag = `${NEXT_CACHE_IMPLICIT_TAG_ID}${pathname}` if (!staticGenerationStore.tags?.includes(tag)) { @@ -332,7 +331,10 @@ function createPatchedFetcher( // we only want to warn if the user is explicitly setting a cache value if (!(isRequestInput && _cache === 'default')) { Log.warn( - `fetch for ${fetchUrl} on ${staticGenerationStore.url.pathname} specified "cache: ${_cache}" and "revalidate: ${curRevalidate}", only one should be specified.` + `fetch for ${fetchUrl} on ${ + staticGenerationStore.url?.pathname ?? + staticGenerationStore.page + } specified "cache: ${_cache}" and "revalidate: ${curRevalidate}", only one should be specified.` ) } _cache = undefined @@ -361,7 +363,7 @@ function createPatchedFetcher( revalidate = validateRevalidate( curRevalidate, - staticGenerationStore.url.pathname + staticGenerationStore.url?.pathname ?? staticGenerationStore.page ) const _headers = getRequestMeta('headers') @@ -687,9 +689,7 @@ function createPatchedFetcher( if (!staticGenerationStore.forceStatic && cache === 'no-store') { const dynamicUsageReason = `no-store fetch ${input}${ - staticGenerationStore.url.pathname - ? ` ${staticGenerationStore.url.pathname}` - : '' + staticGenerationStore.url?.pathname ?? staticGenerationStore.page }` // If enabled, we should bail out of static generation. @@ -723,9 +723,8 @@ function createPatchedFetcher( next.revalidate === 0 ) { const dynamicUsageReason = `revalidate: 0 fetch ${input}${ - staticGenerationStore.url.pathname - ? ` ${staticGenerationStore.url.pathname}` - : '' + staticGenerationStore.url?.pathname ?? + staticGenerationStore.page }` // If enabled, we should bail out of static generation. diff --git a/packages/next/src/server/load-components.ts b/packages/next/src/server/load-components.ts index 3e43beaef8372..c395ee4f94e79 100644 --- a/packages/next/src/server/load-components.ts +++ b/packages/next/src/server/load-components.ts @@ -64,7 +64,7 @@ export type LoadComponentsReturnType = { getStaticPaths?: GetStaticPaths getServerSideProps?: GetServerSideProps ComponentMod: NextModule - routeModule?: RouteModule + routeModule: RouteModule isAppPath?: boolean page: string } diff --git a/packages/next/src/server/load-default-error-components.ts b/packages/next/src/server/load-default-error-components.ts index bbd703709047e..b836aa0aa2e92 100644 --- a/packages/next/src/server/load-default-error-components.ts +++ b/packages/next/src/server/load-default-error-components.ts @@ -40,7 +40,7 @@ export type LoadComponentsReturnType = { getStaticPaths?: GetStaticPaths getServerSideProps?: GetServerSideProps ComponentMod: any - routeModule?: RouteModule + routeModule: RouteModule isAppPath?: boolean page: string } diff --git a/packages/next/src/server/web/spec-extension/revalidate.ts b/packages/next/src/server/web/spec-extension/revalidate.ts index 93e93bff4777a..db8755edd2fd2 100644 --- a/packages/next/src/server/web/spec-extension/revalidate.ts +++ b/packages/next/src/server/web/spec-extension/revalidate.ts @@ -50,7 +50,9 @@ function revalidate(tag: string, expression: string) { if (store.isUnstableCacheCallback) { throw new Error( - `Route ${store.url.pathname} used "${expression}" inside a function cached with "unstable_cache(...)" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering` + `Route ${ + store.url?.pathname ?? store.page + } used "${expression}" inside a function cached with "unstable_cache(...)" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering` ) } diff --git a/packages/next/src/server/web/spec-extension/unstable-cache.ts b/packages/next/src/server/web/spec-extension/unstable-cache.ts index 8e670ad46abdb..7f783239cfcee 100644 --- a/packages/next/src/server/web/spec-extension/unstable-cache.ts +++ b/packages/next/src/server/web/spec-extension/unstable-cache.ts @@ -305,6 +305,7 @@ export function unstable_cache( // when the unstable_cache call is revalidated fetchCache: 'force-no-store', isUnstableCacheCallback: true, + page: '/', url: { pathname: '/', search: '' }, isStaticGeneration: false, prerenderState: null,