From 3a197ecb60de972225d9b328c5c5d224947eacf2 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Sat, 18 Oct 2025 17:22:19 -0700 Subject: [PATCH 1/2] Turbopack: don't fail on export type in use server --- .../src/transforms/server_actions.rs | 120 ++++++++++-------- .../server-actions/server-graph/62/input.ts | 13 ++ .../server-actions/server-graph/62/output.ts | 17 +++ 3 files changed, 100 insertions(+), 50 deletions(-) create mode 100644 crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/input.ts create mode 100644 crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/output.ts diff --git a/crates/next-custom-transforms/src/transforms/server_actions.rs b/crates/next-custom-transforms/src/transforms/server_actions.rs index 7684de6d7823a..0726f83ff1e47 100644 --- a/crates/next-custom-transforms/src/transforms/server_actions.rs +++ b/crates/next-custom-transforms/src/transforms/server_actions.rs @@ -1534,56 +1534,71 @@ impl VisitMut for ServerActions { } } ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named)) => { - if named.src.is_some() { - disallowed_export_span = named.span; - } else { - for spec in &mut named.specifiers { - if let ExportSpecifier::Named(ExportNamedSpecifier { - orig: ModuleExportName::Ident(ident), - exported, - .. - }) = spec - { - if let Some(export_name) = exported { - if let ModuleExportName::Ident(Ident { sym, .. }) = - export_name - { - // export { foo as bar } - self.exported_idents.push(( - ident.clone(), - sym.clone(), - self.generate_server_reference_id( - sym.as_ref(), - in_cache_file, - None, - ), - )); - } else if let ModuleExportName::Str(str) = export_name { - // export { foo as "bar" } - self.exported_idents.push(( - ident.clone(), - str.value.clone(), - self.generate_server_reference_id( - str.value.as_ref(), - in_cache_file, - None, - ), - )); + if !named.type_only { + if named.src.is_some() + && named.specifiers.iter().any(|s| match s { + ExportSpecifier::Namespace(_) | ExportSpecifier::Default(_) => { + true + } + ExportSpecifier::Named(s) => !s.is_type_only, + }) + { + disallowed_export_span = named.span; + } else { + for spec in &mut named.specifiers { + if let ExportSpecifier::Named(ExportNamedSpecifier { + orig: ModuleExportName::Ident(ident), + exported, + is_type_only, + .. + }) = spec + { + if !*is_type_only { + if let Some(export_name) = exported { + if let ModuleExportName::Ident(Ident { + sym, .. + }) = export_name + { + // export { foo as bar } + self.exported_idents.push(( + ident.clone(), + sym.clone(), + self.generate_server_reference_id( + sym.as_ref(), + in_cache_file, + None, + ), + )); + } else if let ModuleExportName::Str(str) = + export_name + { + // export { foo as "bar" } + self.exported_idents.push(( + ident.clone(), + str.value.clone(), + self.generate_server_reference_id( + str.value.as_ref(), + in_cache_file, + None, + ), + )); + } + } else { + // export { foo } + self.exported_idents.push(( + ident.clone(), + ident.sym.clone(), + self.generate_server_reference_id( + ident.sym.as_ref(), + in_cache_file, + None, + ), + )); + } } } else { - // export { foo } - self.exported_idents.push(( - ident.clone(), - ident.sym.clone(), - self.generate_server_reference_id( - ident.sym.as_ref(), - in_cache_file, - None, - ), - )); + disallowed_export_span = named.span; } - } else { - disallowed_export_span = named.span; } } } @@ -1591,7 +1606,6 @@ impl VisitMut for ServerActions { ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(ExportDefaultDecl { decl, span, - .. })) => match decl { DefaultDecl::Fn(f) => { let (is_action_fn, is_cache_fn) = has_body_directive(&f.function.body); @@ -1760,8 +1774,14 @@ impl VisitMut for ServerActions { } } } - ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ExportAll { span, .. })) => { - disallowed_export_span = *span; + ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ExportAll { + span, + type_only, + .. + })) => { + if !*type_only { + disallowed_export_span = *span; + } } _ => {} } diff --git a/crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/input.ts b/crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/input.ts new file mode 100644 index 0000000000000..7a96eeff9cd0f --- /dev/null +++ b/crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/input.ts @@ -0,0 +1,13 @@ +'use server' + +export type X = string +// @ts-ignore -- that file does not exist +export { type A } from './a' +// @ts-ignore -- that file does not exist +export type { B } from './b' +// @ts-ignore -- that file does not exist +export type * from './c' + +export async function actionA(): Promise { + return 'hello from actionA' +} diff --git a/crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/output.ts b/crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/output.ts new file mode 100644 index 0000000000000..af1f4d386df6b --- /dev/null +++ b/crates/next-custom-transforms/tests/fixture/server-actions/server-graph/62/output.ts @@ -0,0 +1,17 @@ +/* __next_internal_action_entry_do_not_use__ {"0095ef8ede0a8a4c822fcbdb018cb264731cb15281":"actionA"} */ import { registerServerReference } from "private-next-rsc-server-reference"; +import { encryptActionBoundArgs, decryptActionBoundArgs } from "private-next-rsc-action-encryption"; +export type X = string; +// @ts-ignore -- that file does not exist +export { type A } from './a'; +// @ts-ignore -- that file does not exist +export type { B } from './b'; +// @ts-ignore -- that file does not exist +export type * from './c'; +export async function actionA(): Promise { + return 'hello from actionA'; +} +import { ensureServerEntryExports } from "private-next-rsc-action-validate"; +ensureServerEntryExports([ + actionA +]); +registerServerReference(actionA, "0095ef8ede0a8a4c822fcbdb018cb264731cb15281", null); From 204cb5d7f0c9a103662f35c9fe059340e14dc79b Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Sat, 18 Oct 2025 18:35:30 -0700 Subject: [PATCH 2/2] fix --- .../src/transforms/server_actions.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/next-custom-transforms/src/transforms/server_actions.rs b/crates/next-custom-transforms/src/transforms/server_actions.rs index 0726f83ff1e47..252151c107ab1 100644 --- a/crates/next-custom-transforms/src/transforms/server_actions.rs +++ b/crates/next-custom-transforms/src/transforms/server_actions.rs @@ -1535,15 +1535,15 @@ impl VisitMut for ServerActions { } ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named)) => { if !named.type_only { - if named.src.is_some() - && named.specifiers.iter().any(|s| match s { + if named.src.is_some() { + if named.specifiers.iter().any(|s| match s { ExportSpecifier::Namespace(_) | ExportSpecifier::Default(_) => { true } ExportSpecifier::Named(s) => !s.is_type_only, - }) - { - disallowed_export_span = named.span; + }) { + disallowed_export_span = named.span; + } } else { for spec in &mut named.specifiers { if let ExportSpecifier::Named(ExportNamedSpecifier {