Scaffolds a new API, `unstable_prefetch()`. It's only allowed in server
code, so we ban it from being imported in the client.
Implementation follows upstack. Intended to be merged together.
Scaffolds a new API, `unstable_navigation()`. It's only allowed in
server code, so we ban it from being imported in the client.
Implementation follows upstack. Intended to be merged together.
Removes the unstable prefix from `unstable_io`. Since this was only
shipped in canaries with the unstable prefix we are going to just remove
it without retaining the unstable prefix simultaneously.
Adds a new export from next/cache that acts as a metasyntactic IO
boundary. During prerendering with cache components it returns a hanging
promise to prevent execution of code that follows it. In all other
contexts it resolves as a fulfilled thenable that React can unwrap
synchronously. This is gated behind experimental.unstableIO and not
ready for general use.
## Summary
Fix dead-code elimination in `packages/next/cache.js` to prevent
server-only internals from being pulled into browser bundles.
Restructures the conditional exports so bundlers can properly tree-shake
server paths.
## Test plan
- [ ] `pnpm --filter=next build` succeeds
- [ ] No runtime behavior changes
---------
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
These are now stable but to allow for graceful upgrading we still export
unstable versions. The unstable version includes a once-warning that
indicates you should upgrade to the stable name.
This provides a way to refresh the client cache from within a server
action. This is useful when you need to refresh the client UI / read
your writes without needing to rely on `updateTag`.
---------
Co-authored-by: JJ Kasper <jj@jjsweb.site>
As discussed we are removing the deprecated field from `revalidateTag`
and `revalidatePath` as they aren't going away anytime soon and the new
`expire` APIs will have slightly different semantics so not a 1-1 rename
with no arguments change anymore. We are also adding the `unstable_`
prefix for `expireTag`/`expirePath` while we iterate on them so it's
clear they will change.
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
This adds `expireTag()` and `expirePath` APIs which are replacing
`revalidateTag` and `revalidatePath`. As such this also marks
`revalidatePath` and `revalidateTag` as deprecated and marked for
removal.
The arguments passed to these methods match `revalidateTag` and
`revalidatePath` with the exception that `expireTag` can receive
multiple tags now as separate arguments which matches our new
`unstable_cacheTag()` API.
We are wanting to update these APIs as `revalidateTag` naming has caused
some confusion as to when the affected items will be updated. The
underlying behavior of `expireTag` is to mark an entry as out of date
and for it to no longer be used so we are expiring it.
If you call `expirePath('/blog/first'`) the next time that item is
requested it is considered expired so the cache will not be used for it
and a fresh entry will be generated. Similarly for `expireTag('posts',
'blog')` the next time any cache with that tag is requested it's
respective cache will not be leveraged and new cache will be populated.
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
This should really be a global config but we don't have an easy way to
get the config from a module. Might need a loader. So this just plumbs
it through a bunch of contexts.
I'm also generate the enum type based on the config.
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
This PR introduces a new API, `unstable_noStore`, which will allow users to declaratively opt out of caching anywhere during static generation in the same way that you can specify `cache: 'no-store'` on a fetch call in Next.js.
An important caveat and difference from just calling `cookies()` to opt-out of static generation is that this won't opt you out when called from within `unstable_cache` and instead defers to the cache configuration to it.
```
import {unstable_noStore as noStore} from 'next/cache';
export default async function Component() {
noStore();
const result = await db.query(...);
}
```