Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit build error when "use cache" is used without dynamicIO enabled #72781

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions crates/next-core/src/next_client/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ 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 mut is_app_dir = false;

match context_ty {
Expand All @@ -72,6 +78,7 @@ pub async fn get_next_client_transforms_rules(
rules.push(get_server_actions_transform_rule(
ActionsTransform::Client,
enable_mdx_rs,
dynamic_io_enabled,
));
}
ClientContextType::Fallback | ClientContextType::Other => {}
Expand Down
9 changes: 9 additions & 0 deletions crates/next-core/src/next_server/transforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ pub async fn get_next_server_transforms_rules(
));
}

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

let mut is_app_dir = false;

let is_server_components = match context_ty {
Expand Down Expand Up @@ -89,6 +95,7 @@ pub async fn get_next_server_transforms_rules(
rules.push(get_server_actions_transform_rule(
ActionsTransform::Client,
mdx_rs,
dynamic_io_enabled,
));

is_app_dir = true;
Expand All @@ -99,6 +106,7 @@ pub async fn get_next_server_transforms_rules(
rules.push(get_server_actions_transform_rule(
ActionsTransform::Server,
mdx_rs,
dynamic_io_enabled,
));

is_app_dir = true;
Expand All @@ -109,6 +117,7 @@ pub async fn get_next_server_transforms_rules(
rules.push(get_server_actions_transform_rule(
ActionsTransform::Server,
mdx_rs,
dynamic_io_enabled,
));

is_app_dir = true;
Expand Down
9 changes: 7 additions & 2 deletions crates/next-core/src/next_shared/transforms/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ pub enum ActionsTransform {
pub fn get_server_actions_transform_rule(
transform: ActionsTransform,
enable_mdx_rs: bool,
dynamic_io_enabled: bool,
) -> ModuleRule {
let transformer =
EcmascriptInputTransform::Plugin(Vc::cell(Box::new(NextServerActions { transform }) as _));
let transformer = EcmascriptInputTransform::Plugin(Vc::cell(Box::new(NextServerActions {
transform,
dynamic_io_enabled,
}) as _));
ModuleRule::new(
module_rule_match_js_no_url(enable_mdx_rs),
vec![ModuleRuleEffect::ExtendEcmascriptTransforms {
Expand All @@ -33,6 +36,7 @@ pub fn get_server_actions_transform_rule(
#[derive(Debug)]
struct NextServerActions {
transform: ActionsTransform,
dynamic_io_enabled: bool,
}

#[async_trait]
Expand All @@ -43,6 +47,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,
hash_salt: "".into(),
},
ctx.comments.clone(),
Expand Down
35 changes: 35 additions & 0 deletions crates/next-custom-transforms/src/transforms/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use swc_core::{
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct Config {
pub is_react_server_layer: bool,
pub dynamic_io_enabled: bool,
pub hash_salt: String,
}

Expand Down Expand Up @@ -265,6 +266,7 @@ impl<C: Comments> ServerActions<C> {
&mut is_action_fn,
&mut cache_type,
&mut span,
self.config.dynamic_io_enabled,
);

if !self.config.is_react_server_layer {
Expand Down Expand Up @@ -1301,6 +1303,7 @@ impl<C: Comments> VisitMut for ServerActions<C> {
&mut self.in_cache_file,
&mut self.has_action,
&mut self.has_cache,
self.config.dynamic_io_enabled,
);

// If we're in a "use cache" file, collect all original IDs from export
Expand Down Expand Up @@ -2355,6 +2358,7 @@ fn remove_server_directive_index_in_module(
in_cache_file: &mut Option<String>,
has_action: &mut bool,
has_cache: &mut bool,
dynamic_io_enabled: bool,
) {
let mut is_directive = true;

Expand Down Expand Up @@ -2383,6 +2387,21 @@ fn remove_server_directive_index_in_module(
// `use cache` or `use cache: foo`
if value == "use cache" || value.starts_with("use cache: ") {
if is_directive {
if !dynamic_io_enabled {
HANDLER.with(|handler| {
handler
.struct_span_err(
*span,
format!(
"To use \"{value}\", please enable the experimental feature flag \"dynamicIO\" in your Next.js config.\n\n\
Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage\n"
)
.as_str(),
)
.emit();
})
}

*in_cache_file = Some(if value == "use cache" {
"default".into()
} else {
Expand Down Expand Up @@ -2518,6 +2537,7 @@ fn remove_server_directive_index_in_fn(
is_action_fn: &mut bool,
cache_type: &mut Option<String>,
action_span: &mut Option<Span>,
dynamic_io_enabled: bool,
) {
let mut is_directive = true;

Expand Down Expand Up @@ -2560,6 +2580,21 @@ fn remove_server_directive_index_in_fn(
});
} else if value == "use cache" || value.starts_with("use cache: ") {
if is_directive {
if !dynamic_io_enabled {
HANDLER.with(|handler| {
handler
.struct_span_err(
*span,
format!(
"To use \"{value}\", please enable the experimental feature flag \"dynamicIO\" in your Next.js config.\n\n\
Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage\n"
)
.as_str(),
)
.emit();
})
}

*cache_type = Some(if value == "use cache" {
"default".into()
} else {
Expand Down
45 changes: 43 additions & 2 deletions crates/next-custom-transforms/tests/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn react_server_actions_server_errors(input: PathBuf) {
FileName::Real(PathBuf::from("/app/item.js")).into(),
Config::WithOptions(Options {
is_react_server_layer: true,
dynamic_io_enabled: false,
dynamic_io_enabled: true,
}),
tr.comments.as_ref().clone(),
None,
Expand All @@ -185,6 +185,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,
hash_salt: "".into(),
},
tr.comments.as_ref().clone(),
Expand Down Expand Up @@ -214,7 +215,7 @@ fn react_server_actions_client_errors(input: PathBuf) {
FileName::Real(PathBuf::from("/app/item.js")).into(),
Config::WithOptions(Options {
is_react_server_layer: false,
dynamic_io_enabled: false,
dynamic_io_enabled: true,
}),
tr.comments.as_ref().clone(),
None,
Expand All @@ -223,6 +224,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,
hash_salt: "".into(),
},
tr.comments.as_ref().clone(),
Expand Down Expand Up @@ -256,3 +258,42 @@ fn next_transform_strip_page_exports_errors(input: PathBuf) {
},
);
}

#[fixture("tests/errors/use-cache-not-allowed/**/input.js")]
fn use_cache_not_allowed(input: PathBuf) {
use next_custom_transforms::transforms::react_server_components::{Config, Options};
let output = input.parent().unwrap().join("output.js");
test_fixture(
syntax(),
&|tr| {
(
resolver(Mark::new(), Mark::new(), false),
server_components(
FileName::Real(PathBuf::from("/app/item.js")).into(),
Config::WithOptions(Options {
is_react_server_layer: true,
dynamic_io_enabled: false,
}),
tr.comments.as_ref().clone(),
None,
),
server_actions(
&FileName::Real("/app/item.js".into()),
server_actions::Config {
is_react_server_layer: true,
dynamic_io_enabled: false,
hash_salt: "".into(),
},
tr.comments.as_ref().clone(),
),
)
},
&input,
&output,
FixtureTestConfig {
allow_error: true,
module: Some(true),
..Default::default()
},
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use cache'

export default async function Page() {
return <p>hello world</p>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* __next_internal_action_entry_do_not_use__ {"803128060c414d59f8552e4788b846c0d2b7f74743":"$$RSC_SERVER_CACHE_0"} */ import { registerServerReference } from "private-next-rsc-server-reference";
import { encryptActionBoundArgs, decryptActionBoundArgs } from "private-next-rsc-action-encryption";
import { cache as $$cache__ } from "private-next-rsc-cache-wrapper";
export var $$RSC_SERVER_CACHE_0 = $$cache__("default", "803128060c414d59f8552e4788b846c0d2b7f74743", 0, async function Page() {
return <p>hello world</p>;
});
Object.defineProperty($$RSC_SERVER_CACHE_0, "name", {
"value": "Page",
"writable": false
});
export default registerServerReference($$RSC_SERVER_CACHE_0, "803128060c414d59f8552e4788b846c0d2b7f74743", null);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x To use "use cache", please enable the experimental feature flag "dynamicIO" in your Next.js config.
|
| Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage
|
,-[input.js:1:1]
1 | 'use cache'
: ^^^^^^^^^^^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default async function Page() {
'use cache: x'

return <p>hello world</p>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* __next_internal_action_entry_do_not_use__ {"803128060c414d59f8552e4788b846c0d2b7f74743":"$$RSC_SERVER_CACHE_0"} */ import { registerServerReference } from "private-next-rsc-server-reference";
import { encryptActionBoundArgs, decryptActionBoundArgs } from "private-next-rsc-action-encryption";
import { cache as $$cache__ } from "private-next-rsc-cache-wrapper";
export var $$RSC_SERVER_CACHE_0 = $$cache__("x", "803128060c414d59f8552e4788b846c0d2b7f74743", 0, async function Page() {
return <p>hello world</p>;
});
Object.defineProperty($$RSC_SERVER_CACHE_0, "name", {
"value": "Page",
"writable": false
});
export default registerServerReference($$RSC_SERVER_CACHE_0, "803128060c414d59f8552e4788b846c0d2b7f74743", null);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
x To use "use cache: x", please enable the experimental feature flag "dynamicIO" in your Next.js config.
|
| Read more: https://nextjs.org/docs/canary/app/api-reference/directives/use-cache#usage
|
,-[input.js:2:1]
1 | export default async function Page() {
2 | 'use cache: x'
: ^^^^^^^^^^^^^^
`----
3 changes: 3 additions & 0 deletions crates/next-custom-transforms/tests/fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,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,
hash_salt: "".into(),
},
_tr.comments.as_ref().clone(),
Expand Down Expand Up @@ -445,6 +446,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,
hash_salt: "".into(),
},
_tr.comments.as_ref().clone(),
Expand All @@ -469,6 +471,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,
hash_salt: "".into(),
},
_tr.comments.as_ref().clone(),
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/swc/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ function getBaseSWCOptions({
isAppRouterPagesLayer && !jest
? {
isReactServerLayer,
dynamicIoEnabled: isDynamicIo,
hashSalt: serverReferenceHashSalt,
}
: undefined,
Expand Down
5 changes: 0 additions & 5 deletions packages/next/src/server/use-cache/use-cache-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,6 @@ export function cache(
boundArgsLength: number,
fn: any
) {
if (!process.env.__NEXT_DYNAMIC_IO) {
throw new Error(
'"use cache" is only available with the experimental.dynamicIO config.'
)
}
for (const [key, value] of Object.entries(
_globalThis.__nextCacheHandlers || {}
)) {
Expand Down
8 changes: 8 additions & 0 deletions test/e2e/app-dir/use-cache-without-dynamic-io/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ReactNode } from 'react'
export default function Root({ children }: { children: ReactNode }) {
return (
<html>
<body>{children}</body>
</html>
)
}
5 changes: 5 additions & 0 deletions test/e2e/app-dir/use-cache-without-dynamic-io/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use cache'

export default async function Page() {
return <p>hello world</p>
}
6 changes: 6 additions & 0 deletions test/e2e/app-dir/use-cache-without-dynamic-io/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {}

module.exports = nextConfig
Loading
Loading