Skip to content

Commit

Permalink
Emit build error for unknown cache kinds (#72832)
Browse files Browse the repository at this point in the history
When a `"use cache"` directive with a custom cache kind is used, e.g.
`"use cache: custom"`, a cache handler with the same name must be
specified in the Next.js config:

```js
/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  experimental: {
    dynamicIO: true,
    cacheHandlers: {
      custom: require.resolve('path/to/custom/cache/handler'),
    },
  },
}

module.exports = nextConfig
```

If this is not the case, we emit a build error with an error message
that explains this requirement.

<img width="795" alt="Screenshot 2024-11-14 at 23 30 01"
src="https://github.com/user-attachments/assets/bd138c97-608f-42ce-abb2-edb3e44edc3f">

When we'll get a docs page for this experimental config, we will add the
usual "Read more: ..." hint as well.

---------

Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
Co-authored-by: Janka Uryga <lolzatu2@gmail.com>
  • Loading branch information
3 people authored Nov 17, 2024
1 parent ef9d096 commit d54122a
Show file tree
Hide file tree
Showing 22 changed files with 390 additions and 82 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 3 additions & 6 deletions crates/next-core/src/next_client/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,8 @@ pub async fn get_next_client_transforms_rules(
rules.push(get_debug_fn_name_rule(enable_mdx_rs));
}

let dynamic_io_enabled = next_config
.experimental()
.await?
.dynamic_io
.unwrap_or(false);

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

match context_ty {
Expand All @@ -79,6 +75,7 @@ pub async fn get_next_client_transforms_rules(
ActionsTransform::Client,
enable_mdx_rs,
dynamic_io_enabled,
cache_kinds,
));
}
ClientContextType::Fallback | ClientContextType::Other => {}
Expand Down
29 changes: 24 additions & 5 deletions crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashSet;

use anyhow::{bail, Context, Result};
use rustc_hash::FxHashSet;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value as JsonValue;
use turbo_rcstr::RcStr;
Expand Down Expand Up @@ -40,6 +41,9 @@ struct CustomRoutes {
#[turbo_tasks::value(transparent)]
pub struct ModularizeImports(FxIndexMap<String, ModularizeImportPackageConfig>);

#[turbo_tasks::value(transparent)]
pub struct CacheKinds(FxHashSet<RcStr>);

#[turbo_tasks::value(serialization = "custom", eq = "manual")]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -520,7 +524,7 @@ pub struct ExperimentalConfig {
pub sri: Option<SubResourceIntegrity>,
react_compiler: Option<ReactCompilerOptionsOrBoolean>,
#[serde(rename = "dynamicIO")]
pub dynamic_io: Option<bool>,
dynamic_io: Option<bool>,
// ---
// UNSUPPORTED
// ---
Expand All @@ -529,6 +533,7 @@ pub struct ExperimentalConfig {
after: Option<bool>,
amp: Option<serde_json::Value>,
app_document_preloading: Option<bool>,
cache_handlers: Option<FxIndexMap<RcStr, RcStr>>,
cache_life: Option<FxIndexMap<String, CacheLifeProfile>>,
case_sensitive_routes: Option<bool>,
cpus: Option<f64>,
Expand Down Expand Up @@ -1150,10 +1155,24 @@ impl NextConfig {
}

#[turbo_tasks::function]
pub async fn enable_react_owner_stack(self: Vc<Self>) -> Result<Vc<bool>> {
Ok(Vc::cell(
self.await?.experimental.react_owner_stack.unwrap_or(false),
))
pub fn enable_react_owner_stack(&self) -> Vc<bool> {
Vc::cell(self.experimental.react_owner_stack.unwrap_or(false))
}

#[turbo_tasks::function]
pub fn enable_dynamic_io(&self) -> Vc<bool> {
Vc::cell(self.experimental.dynamic_io.unwrap_or(false))
}

#[turbo_tasks::function]
pub fn cache_kinds(&self) -> Vc<CacheKinds> {
Vc::cell(
self.experimental
.cache_handlers
.as_ref()
.map(|handlers| handlers.keys().cloned().collect())
.unwrap_or_default(),
)
}

#[turbo_tasks::function]
Expand Down
11 changes: 5 additions & 6 deletions crates/next-core/src/next_server/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,8 @@ pub async fn get_next_server_transforms_rules(
));
}

let dynamic_io_enabled = next_config
.experimental()
.await?
.dynamic_io
.unwrap_or(false);

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

let is_server_components = match context_ty {
Expand Down Expand Up @@ -96,6 +92,7 @@ pub async fn get_next_server_transforms_rules(
ActionsTransform::Client,
mdx_rs,
dynamic_io_enabled,
cache_kinds,
));

is_app_dir = true;
Expand All @@ -107,6 +104,7 @@ pub async fn get_next_server_transforms_rules(
ActionsTransform::Server,
mdx_rs,
dynamic_io_enabled,
cache_kinds,
));

is_app_dir = true;
Expand All @@ -118,6 +116,7 @@ pub async fn get_next_server_transforms_rules(
ActionsTransform::Server,
mdx_rs,
dynamic_io_enabled,
cache_kinds,
));

is_app_dir = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,7 @@ pub async fn get_next_react_server_components_transform_rule(
app_dir: Option<Vc<FileSystemPath>>,
) -> Result<ModuleRule> {
let enable_mdx_rs = next_config.mdx_rs().await?.is_some();
let dynamic_io_enabled = next_config
.experimental()
.await?
.dynamic_io
.unwrap_or(false);
let dynamic_io_enabled = *next_config.enable_dynamic_io().await?;
Ok(get_ecma_transform_rule(
Box::new(NextJsReactServerComponents::new(
is_react_server_layer,
Expand Down
5 changes: 5 additions & 0 deletions crates/next-core/src/next_shared/transforms/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use turbopack::module_options::{ModuleRule, ModuleRuleEffect};
use turbopack_ecmascript::{CustomTransformer, EcmascriptInputTransform, TransformContext};

use super::module_rule_match_js_no_url;
use crate::next_config::CacheKinds;

#[derive(Debug)]
pub enum ActionsTransform {
Expand All @@ -19,11 +20,13 @@ pub fn get_server_actions_transform_rule(
transform: ActionsTransform,
enable_mdx_rs: bool,
dynamic_io_enabled: bool,
cache_kinds: ResolvedVc<CacheKinds>,
) -> ModuleRule {
let transformer =
EcmascriptInputTransform::Plugin(ResolvedVc::cell(Box::new(NextServerActions {
transform,
dynamic_io_enabled,
cache_kinds,
}) as _));
ModuleRule::new(
module_rule_match_js_no_url(enable_mdx_rs),
Expand All @@ -38,6 +41,7 @@ pub fn get_server_actions_transform_rule(
struct NextServerActions {
transform: ActionsTransform,
dynamic_io_enabled: bool,
cache_kinds: ResolvedVc<CacheKinds>,
}

#[async_trait]
Expand All @@ -50,6 +54,7 @@ impl CustomTransformer for NextServerActions {
is_react_server_layer: matches!(self.transform, ActionsTransform::Server),
dynamic_io_enabled: self.dynamic_io_enabled,
hash_salt: "".into(),
cache_kinds: self.cache_kinds.await?.clone_value(),
},
ctx.comments.clone(),
);
Expand Down
1 change: 1 addition & 0 deletions crates/next-custom-transforms/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ styled_jsx = { workspace = true }
swc_emotion = { workspace = true }
swc_relay = { workspace = true }
turbopack-ecmascript-plugins = { workspace = true, optional = true }
turbo-rcstr = { workspace = true }

react_remove_properties = "0.24.25"
remove_console = "0.25.25"
Expand Down
Loading

0 comments on commit d54122a

Please sign in to comment.