-
Notifications
You must be signed in to change notification settings - Fork 26.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
formalizes the concept of dynamic APIs inside Next to allow for varying semantics beyond just staticGenerationBailout. ### Dynamic APIs #### `markCurrentScopeAsDynamic` useful to bail out of default caching semantics but does not imply a Request specific data source was read. critically, this semantic is ignored if you are inside a cache scope #### `trackDynamicDataAccessed` Must be called before reading any data source that is derived from Request specific data. Currently this is `cookies()`, `headers()`, and `searchParams`. This kind of data access inside a cache scope is forbidden (it always should have been, but now it will error). #### `trackDynamicFetch` This one is unideal but the complexity of patch-fetch's current implementation necessitates it for now. Essentially it will postpone if we are prerendering. Long term this should be eliminated with a refactor of patch fetch. ### Other Improvements Also removes the `staticGenerationBailout` implementation as it has been replaced with more specific logic in the places it was previously being used. One area that has also been enhanced is the proxy for app-route modules. Previously we proxied the Request every time however when we are doing non-static generation executions we generally don't want the overhead of wrapping the request. In the refactor here I also improved the runtime performance by using static proxy handlers and I believe I also fixed a few bugs related to `clone` and `url` In general there has been a bit of refactoring to clarify how we should handle various render/execution states and a reduction in implicit side effects for proper execution. Another callout to notice is that app-route modules do not attempt a static generation if they are force-dynamic regardless of the PPR setting. Previously the PPR setting would opt them into this code path which is not necessary because PPR itself does not work for routes, only pages. Closes NEXT-2099
- Loading branch information
Showing
52 changed files
with
1,831 additions
and
666 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache' | ||
export { revalidatePath } from 'next/dist/server/web/spec-extension/revalidate-path' | ||
export { revalidateTag } from 'next/dist/server/web/spec-extension/revalidate-tag' | ||
export { | ||
revalidateTag, | ||
revalidatePath, | ||
} from 'next/dist/server/web/spec-extension/revalidate' | ||
export { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
'use client' | ||
import { createDynamicallyTrackedSearchParams } from './search-params' | ||
|
||
export function ClientPageRoot({ | ||
Component, | ||
props, | ||
}: { | ||
Component: React.ComponentType<any> | ||
props: { [props: string]: any } | ||
}) { | ||
// We expect to be passed searchParams but even if we aren't we can construct one from | ||
// an empty object. We only do this if we are in a static generation as a performance | ||
// optimization. Ideally we'd unconditionally construct the tracked params but since | ||
// this creates a proxy which is slow and this would happen even for client navigations | ||
// that are done entirely dynamically and we know there the dynamic tracking is a noop | ||
// in this dynamic case we can safely elide it. | ||
props.searchParams = createDynamicallyTrackedSearchParams( | ||
props.searchParams || {} | ||
) | ||
return <Component {...props} /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import type { ParsedUrlQuery } from 'querystring' | ||
|
||
import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' | ||
import { trackDynamicDataAccessed } from '../../server/app-render/dynamic-rendering' | ||
import { ReflectAdapter } from '../../server/web/spec-extension/adapters/reflect' | ||
|
||
/** | ||
* Takes a ParsedUrlQuery object and either returns it unmodified or returns an empty object | ||
* | ||
* Even though we do not track read access on the returned searchParams we need to | ||
* return an empty object if we are doing a 'force-static' render. This is to ensure | ||
* we don't encode the searchParams into the flight data. | ||
*/ | ||
export function createUntrackedSearchParams( | ||
searchParams: ParsedUrlQuery | ||
): ParsedUrlQuery { | ||
const store = staticGenerationAsyncStorage.getStore() | ||
if (store && store.forceStatic) { | ||
return {} | ||
} else { | ||
return searchParams | ||
} | ||
} | ||
|
||
/** | ||
* Takes a ParsedUrlQuery object and returns a Proxy that tracks read access to the object | ||
* | ||
* If running in the browser will always return the provided searchParams object. | ||
* When running during SSR will return empty during a 'force-static' render and | ||
* otherwise it returns a searchParams object which tracks reads to trigger dynamic rendering | ||
* behavior if appropriate | ||
*/ | ||
export function createDynamicallyTrackedSearchParams( | ||
searchParams: ParsedUrlQuery | ||
): ParsedUrlQuery { | ||
const store = staticGenerationAsyncStorage.getStore() | ||
if (!store) { | ||
// we assume we are in a route handler or page render. just return the searchParams | ||
return searchParams | ||
} else if (store.forceStatic) { | ||
// If we forced static we omit searchParams entirely. This is true both during SSR | ||
// and browser render because we need there to be parity between these environments | ||
return {} | ||
} else if (!store.isStaticGeneration && !store.dynamicShouldError) { | ||
// during dynamic renders we don't actually have to track anything so we just return | ||
// the searchParams directly. However if dynamic data access should error then we | ||
// still want to track access. This covers the case in Dev where all renders are dynamic | ||
// but we still want to error if you use a dynamic data source because it will fail the build | ||
// or revalidate if you do. | ||
return searchParams | ||
} else { | ||
// We need to track dynamic access with a Proxy. We implement get, has, and ownKeys because | ||
// these can all be used to exfiltrate information about searchParams. | ||
return new Proxy({} as ParsedUrlQuery, { | ||
get(target, prop, receiver) { | ||
if (typeof prop === 'string') { | ||
trackDynamicDataAccessed(store, `searchParams.${prop}`) | ||
} | ||
return ReflectAdapter.get(target, prop, receiver) | ||
}, | ||
has(target, prop) { | ||
if (typeof prop === 'string') { | ||
trackDynamicDataAccessed(store, `searchParams.${prop}`) | ||
} | ||
return Reflect.has(target, prop) | ||
}, | ||
ownKeys(target) { | ||
trackDynamicDataAccessed(store, 'searchParams') | ||
return Reflect.ownKeys(target) | ||
}, | ||
}) | ||
} | ||
} |
15 changes: 0 additions & 15 deletions
15
packages/next/src/client/components/searchparams-bailout-proxy.ts
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.