Skip to content

Commit

Permalink
Introduce standalone experimental.useCache flag (#75240)
Browse files Browse the repository at this point in the history
  • Loading branch information
unstubbable authored Jan 23, 2025
1 parent 8b71caa commit bf726d3
Show file tree
Hide file tree
Showing 37 changed files with 318 additions and 259 deletions.
4 changes: 2 additions & 2 deletions crates/next-core/src/next_client/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub async fn get_next_client_transforms_rules(
rules.push(get_debug_fn_name_rule(enable_mdx_rs));
}

let dynamic_io_enabled = *next_config.enable_dynamic_io().await?;
let use_cache_enabled = *next_config.enable_use_cache().await?;
let cache_kinds = next_config.cache_kinds().to_resolved().await?;
let mut is_app_dir = false;

Expand Down Expand Up @@ -77,7 +77,7 @@ pub async fn get_next_client_transforms_rules(
ActionsTransform::Client,
encryption_key,
enable_mdx_rs,
dynamic_io_enabled,
use_cache_enabled,
cache_kinds,
));
}
Expand Down
13 changes: 13 additions & 0 deletions crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ pub struct ExperimentalConfig {
react_compiler: Option<ReactCompilerOptionsOrBoolean>,
#[serde(rename = "dynamicIO")]
dynamic_io: Option<bool>,
use_cache: Option<bool>,
// ---
// UNSUPPORTED
// ---
Expand Down Expand Up @@ -1408,6 +1409,18 @@ impl NextConfig {
Vc::cell(self.experimental.dynamic_io.unwrap_or(false))
}

#[turbo_tasks::function]
pub fn enable_use_cache(&self) -> Vc<bool> {
Vc::cell(
self.experimental
.use_cache
// "use cache" was originally implicitly enabled with the
// dynamicIO flag, so we transfer the value for dynamicIO to the
// explicit useCache flag to ensure backwards compatibility.
.unwrap_or(self.experimental.dynamic_io.unwrap_or(false)),
)
}

#[turbo_tasks::function]
pub fn cache_kinds(&self) -> Vc<CacheKinds> {
Vc::cell(
Expand Down
8 changes: 4 additions & 4 deletions crates/next-core/src/next_server/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub async fn get_next_server_transforms_rules(
));
}

let dynamic_io_enabled = *next_config.enable_dynamic_io().await?;
let use_cache_enabled = *next_config.enable_use_cache().await?;
let cache_kinds = next_config.cache_kinds().to_resolved().await?;
let mut is_app_dir = false;

Expand Down Expand Up @@ -115,7 +115,7 @@ pub async fn get_next_server_transforms_rules(
ActionsTransform::Client,
encryption_key,
mdx_rs,
dynamic_io_enabled,
use_cache_enabled,
cache_kinds,
));

Expand All @@ -128,7 +128,7 @@ pub async fn get_next_server_transforms_rules(
ActionsTransform::Server,
encryption_key,
mdx_rs,
dynamic_io_enabled,
use_cache_enabled,
cache_kinds,
));

Expand All @@ -141,7 +141,7 @@ pub async fn get_next_server_transforms_rules(
ActionsTransform::Server,
encryption_key,
mdx_rs,
dynamic_io_enabled,
use_cache_enabled,
cache_kinds,
));

Expand Down
8 changes: 4 additions & 4 deletions crates/next-core/src/next_shared/transforms/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ pub fn get_server_actions_transform_rule(
transform: ActionsTransform,
encryption_key: ResolvedVc<RcStr>,
enable_mdx_rs: bool,
dynamic_io_enabled: bool,
use_cache_enabled: bool,
cache_kinds: ResolvedVc<CacheKinds>,
) -> ModuleRule {
let transformer =
EcmascriptInputTransform::Plugin(ResolvedVc::cell(Box::new(NextServerActions {
transform,
encryption_key,
dynamic_io_enabled,
use_cache_enabled,
cache_kinds,
}) as _));
ModuleRule::new(
Expand All @@ -44,7 +44,7 @@ pub fn get_server_actions_transform_rule(
struct NextServerActions {
transform: ActionsTransform,
encryption_key: ResolvedVc<RcStr>,
dynamic_io_enabled: bool,
use_cache_enabled: bool,
cache_kinds: ResolvedVc<CacheKinds>,
}

Expand All @@ -56,7 +56,7 @@ impl CustomTransformer for NextServerActions {
&FileName::Real(ctx.file_path_str.into()),
Config {
is_react_server_layer: matches!(self.transform, ActionsTransform::Server),
dynamic_io_enabled: self.dynamic_io_enabled,
use_cache_enabled: self.use_cache_enabled,
hash_salt: self.encryption_key.await?.to_string(),
cache_kinds: self.cache_kinds.await?.clone_value(),
},
Expand Down
12 changes: 6 additions & 6 deletions crates/next-custom-transforms/src/transforms/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use turbo_rcstr::RcStr;
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct Config {
pub is_react_server_layer: bool,
pub dynamic_io_enabled: bool,
pub use_cache_enabled: bool,
pub hash_salt: String,
pub cache_kinds: FxHashSet<RcStr>,
}
Expand Down Expand Up @@ -104,7 +104,7 @@ enum ServerActionsErrorKind {
span: Span,
cache_kind: RcStr,
},
UseCacheWithoutDynamicIO {
UseCacheWithoutExperimentalFlag {
span: Span,
directive: String,
},
Expand Down Expand Up @@ -2684,8 +2684,8 @@ impl DirectiveVisitor<'_> {
location: self.location.clone(),
});
} else if self.is_allowed_position {
if !self.config.dynamic_io_enabled {
emit_error(ServerActionsErrorKind::UseCacheWithoutDynamicIO {
if !self.config.use_cache_enabled {
emit_error(ServerActionsErrorKind::UseCacheWithoutExperimentalFlag {
span: *span,
directive: value.to_string(),
});
Expand Down Expand Up @@ -3094,11 +3094,11 @@ fn emit_error(error_kind: ServerActionsErrorKind) {
"#
},
),
ServerActionsErrorKind::UseCacheWithoutDynamicIO { span, directive } => (
ServerActionsErrorKind::UseCacheWithoutExperimentalFlag { span, directive } => (
span,
formatdoc! {
r#"
To use "{directive}", please enable the experimental feature flag "dynamicIO" in your Next.js config.
To use "{directive}", please enable the experimental feature flag "useCache" in your Next.js config.
Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage
"#
Expand Down
6 changes: 3 additions & 3 deletions crates/next-custom-transforms/tests/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ fn react_server_actions_server_errors(input: PathBuf) {
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: true,
dynamic_io_enabled: true,
use_cache_enabled: true,
hash_salt: "".into(),
cache_kinds: FxHashSet::default(),
},
Expand Down Expand Up @@ -227,7 +227,7 @@ fn react_server_actions_client_errors(input: PathBuf) {
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: false,
dynamic_io_enabled: true,
use_cache_enabled: true,
hash_salt: "".into(),
cache_kinds: FxHashSet::default(),
},
Expand Down Expand Up @@ -286,7 +286,7 @@ fn use_cache_not_allowed(input: PathBuf) {
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: true,
dynamic_io_enabled: false,
use_cache_enabled: false,
hash_salt: "".into(),
cache_kinds: FxHashSet::from_iter(["x".into()]),
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
x To use "use cache", please enable the experimental feature flag "dynamicIO" in your Next.js config.
x To use "use cache", please enable the experimental feature flag "useCache" in your Next.js config.
|
| Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
x To use "use cache: x", please enable the experimental feature flag "dynamicIO" in your Next.js config.
x To use "use cache: x", please enable the experimental feature flag "useCache" in your Next.js config.
|
| Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage
|
Expand Down
8 changes: 4 additions & 4 deletions crates/next-custom-transforms/tests/fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ fn server_actions_server_fixture(input: PathBuf) {
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: true,
dynamic_io_enabled: true,
use_cache_enabled: true,
hash_salt: "".into(),
cache_kinds: FxHashSet::from_iter(["x".into()]),
},
Expand Down Expand Up @@ -601,7 +601,7 @@ fn next_font_with_directive_fixture(input: PathBuf) {
&FileName::Real("/app/test.tsx".into()),
server_actions::Config {
is_react_server_layer: true,
dynamic_io_enabled: true,
use_cache_enabled: true,
hash_salt: "".into(),
cache_kinds: FxHashSet::default(),
},
Expand All @@ -628,7 +628,7 @@ fn server_actions_client_fixture(input: PathBuf) {
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: false,
dynamic_io_enabled: true,
use_cache_enabled: true,
hash_salt: "".into(),
cache_kinds: FxHashSet::default(),
},
Expand Down Expand Up @@ -931,7 +931,7 @@ fn test_source_maps(input: PathBuf) {
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: true,
dynamic_io_enabled: true,
use_cache_enabled: true,
hash_salt: "".into(),
cache_kinds: FxHashSet::from_iter([]),
},
Expand Down
10 changes: 6 additions & 4 deletions docs/01-app/04-api-reference/01-directives/use-cache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ related:
title: Related
description: View related API references.
links:
- app/api-reference/config/next-config-js/useCache
- app/api-reference/config/next-config-js/dynamicIO
- app/api-reference/config/next-config-js/cacheLife
- app/api-reference/functions/cacheTag
Expand All @@ -17,14 +18,14 @@ The `use cache` directive designates a component and/or a function to be cached.

## Usage

Enable support for the `use cache` directive with the [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO) flag in your `next.config.ts` file:
Enable support for the `use cache` directive with the [`useCache`](/docs/app/api-reference/config/next-config-js/useCache) flag in your `next.config.ts` file:

```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
experimental: {
dynamicIO: true,
useCache: true,
},
}

Expand All @@ -35,13 +36,15 @@ export default nextConfig
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
dynamicIO: true,
useCache: true,
},
}

module.exports = nextConfig
```

Additionally, `use cache` directives are also enabled when the [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO) flag is set.

Then, you can use the `use cache` directive at the file, component, or function level:

```tsx
Expand Down Expand Up @@ -75,7 +78,6 @@ export async function getData() {
- The return value of the cacheable function must also be serializable. This ensures that the cached data can be stored and retrieved correctly.
- Functions that use the `use cache` directive must not have any side-effects, such as modifying state, directly manipulating the DOM, or setting timers to execute code at intervals.
- If used alongside [Partial Prerendering](/docs/app/building-your-application/rendering/partial-prerendering), segments that have `use cache` will be prerendered as part of the static HTML shell.
- The `use cache` directive will be available separately from the [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO) flag in the future.
- Unlike [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache) which only supports JSON data, `use cache` can cache any serializable data React can render, including the render output of components.

## Examples
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: useCache
description: Learn how to enable the useCache flag in Next.js.
version: canary
---

The `useCache` flag is an experimental feature in Next.js that enables the [`use cache` directive](/docs/app/api-reference/directives/use-cache) to be used independently of [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO). When enabled, you can use `use cache` in your application even if `dynamicIO` is turned off.

## Usage

To enable the `useCache` flag, set it to `true` in the `experimental` section of your `next.config.ts` file:

```ts filename="next.config.ts"
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
}

export default nextConfig
```

When `useCache` is enabled, you can use the following cache functions and configurations:

- The [`use cache` directive](/docs/app/api-reference/directives/use-cache)
- The [`cacheLife` function](/docs/app/api-reference/config/next-config-js/cacheLife) with `use cache`
- The [`cacheTag` function](/docs/app/api-reference/functions/cacheTag)
4 changes: 3 additions & 1 deletion packages/next/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -624,5 +624,7 @@
"623": "Invalid quality prop (%s) on \\`next/image\\` does not match \\`images.qualities\\` configured in your \\`next.config.js\\`\\nSee more info: https://nextjs.org/docs/messages/next-image-unconfigured-qualities",
"624": "Internal Next.js Error: createMutableActionQueue was called more than once",
"625": "Server Actions are not supported with static export.\\nRead more: https://nextjs.org/docs/app/building-your-application/deploying/static-exports#unsupported-features",
"626": "Intercepting routes are not supported with static export.\\nRead more: https://nextjs.org/docs/app/building-your-application/deploying/static-exports#unsupported-features"
"626": "Intercepting routes are not supported with static export.\\nRead more: https://nextjs.org/docs/app/building-your-application/deploying/static-exports#unsupported-features",
"627": "cacheLife() is only available with the experimental.useCache config.",
"628": "cacheTag() is only available with the experimental.useCache config."
}
1 change: 0 additions & 1 deletion packages/next/src/build/static-paths/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ export async function buildAppStaticPaths({
const incrementalCache = await createIncrementalCache({
dir,
distDir,
dynamicIO,
cacheHandler,
cacheHandlers,
requestHeaders,
Expand Down
7 changes: 6 additions & 1 deletion packages/next/src/build/swc/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function getBaseSWCOptions({
bundleLayer,
isDynamicIo,
cacheHandlers,
useCacheEnabled,
}: {
filename: string
jest?: boolean
Expand All @@ -89,6 +90,7 @@ function getBaseSWCOptions({
bundleLayer?: WebpackLayerName
isDynamicIo?: boolean
cacheHandlers?: ExperimentalConfig['cacheHandlers']
useCacheEnabled?: boolean
}) {
const isReactServerLayer = isWebpackServerOnlyLayer(bundleLayer)
const isAppRouterPagesLayer = isWebpackAppPagesLayer(bundleLayer)
Expand Down Expand Up @@ -216,7 +218,7 @@ function getBaseSWCOptions({
isAppRouterPagesLayer && !jest
? {
isReactServerLayer,
dynamicIoEnabled: isDynamicIo,
useCacheEnabled,
hashSalt: serverReferenceHashSalt,
cacheKinds: cacheHandlers ? Object.keys(cacheHandlers) : [],
}
Expand Down Expand Up @@ -364,6 +366,7 @@ export function getLoaderSWCOptions({
bundleLayer,
esm,
cacheHandlers,
useCacheEnabled,
}: {
filename: string
development: boolean
Expand All @@ -389,6 +392,7 @@ export function getLoaderSWCOptions({
serverReferenceHashSalt: string
bundleLayer?: WebpackLayerName
cacheHandlers: ExperimentalConfig['cacheHandlers']
useCacheEnabled?: boolean
}) {
let baseOptions: any = getBaseSWCOptions({
filename,
Expand All @@ -407,6 +411,7 @@ export function getLoaderSWCOptions({
esm: !!esm,
isDynamicIo,
cacheHandlers,
useCacheEnabled,
})
baseOptions.fontLoaders = {
fontLoaders: ['next/font/local', 'next/font/google'],
Expand Down
1 change: 0 additions & 1 deletion packages/next/src/build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,6 @@ export async function isPageStatic({
cacheHandlers,
distDir,
dir,
dynamicIO,
flushToDisk: isrFlushToDisk,
cacheMaxMemorySize: maxMemoryCacheSize,
})
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/webpack/loaders/next-swc-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ async function loaderTransform(
bundleLayer,
esm,
cacheHandlers: nextConfig.experimental?.cacheHandlers,
useCacheEnabled: nextConfig.experimental?.useCache,
})

const programmaticOptions = {
Expand Down
Loading

0 comments on commit bf726d3

Please sign in to comment.