Skip to content

Commit a9b691e

Browse files
committed
collect actions for the right runtime only
1 parent 854fea2 commit a9b691e

File tree

8 files changed

+122
-70
lines changed

8 files changed

+122
-70
lines changed

crates/next-api/src/app.rs

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use turbopack_core::{
5555
},
5656
file_source::FileSource,
5757
ident::{AssetIdent, Layer},
58-
module::Module,
58+
module::{Module, Modules},
5959
module_graph::{
6060
GraphEntries, ModuleGraph, SingleModuleGraph, VisitedModules,
6161
binding_usage_info::compute_binding_usage_info,
@@ -973,7 +973,7 @@ impl AppProject {
973973
pub async fn app_module_graph(
974974
&self,
975975
rsc_entry: ResolvedVc<Box<dyn Module>>,
976-
server_action_loader_module: ResolvedVc<Box<dyn Module>>,
976+
server_action_loader_modules: ResolvedVc<Modules>,
977977
client_shared_entries: Vc<EvaluatableAssets>,
978978
has_layout_segments: bool,
979979
) -> Result<Vc<ModuleGraph>> {
@@ -991,8 +991,14 @@ impl AppProject {
991991
// Implements layout segment optimization to compute a graph "chain" for each layout
992992
// segment
993993
async move {
994-
let rsc_entry_chunk_group =
995-
ChunkGroupEntry::Entry(vec![server_action_loader_module, rsc_entry]);
994+
let rsc_entry_chunk_group = ChunkGroupEntry::Entry(
995+
server_action_loader_modules
996+
.await?
997+
.iter()
998+
.copied()
999+
.chain(std::iter::once(rsc_entry))
1000+
.collect(),
1001+
);
9961002

9971003
let mut graphs = vec![];
9981004
let visited_modules = if has_layout_segments {
@@ -1279,15 +1285,36 @@ impl AppEndpoint {
12791285
}
12801286

12811287
#[turbo_tasks::function]
1282-
async fn server_action_loader_module(self: Vc<Self>) -> Result<Vc<Box<dyn Module>>> {
1288+
async fn server_action_loader_modules(self: Vc<Self>) -> Result<Vc<Modules>> {
12831289
let this = self.await?;
1284-
// let app_entry = self.app_endpoint_entry().await?;
1285-
// let runtime = app_entry.config.await?.runtime.unwrap_or_default();
1290+
let app_entry = self.app_endpoint_entry().await?;
1291+
let runtime = app_entry.config.await?.runtime.unwrap_or_default();
12861292

1287-
Ok(Vc::upcast(ServerActionCollectModule::new(
1288-
rcstr!("next/server-actions"),
1289-
this.page.to_string().into(),
1290-
)))
1293+
Ok(Vc::cell(vec![
1294+
// Collect inline "use server" function inside of RSC modules
1295+
ResolvedVc::upcast(
1296+
ServerActionCollectModule::new(
1297+
rcstr!("next/server-actions"),
1298+
this.page.to_string().into(),
1299+
)
1300+
.to_resolved()
1301+
.await?,
1302+
),
1303+
// Collect "use server" modules imported from client components.
1304+
// By only collecting the correct runtime, modules emitted for the other runtime are
1305+
// never even compiled.
1306+
ResolvedVc::upcast(
1307+
ServerActionCollectModule::new(
1308+
match runtime {
1309+
NextRuntime::NodeJs => rcstr!("next/server-actions/node"),
1310+
NextRuntime::Edge => rcstr!("next/server-actions/edge"),
1311+
},
1312+
this.page.to_string().into(),
1313+
)
1314+
.to_resolved()
1315+
.await?,
1316+
),
1317+
]))
12911318
}
12921319

12931320
#[turbo_tasks::function]
@@ -1342,11 +1369,11 @@ impl AppEndpoint {
13421369

13431370
let is_app_page = matches!(this.ty, AppEndpointType::Page { .. });
13441371

1345-
let server_action_loader = self.server_action_loader_module();
1372+
let server_action_loader_modules = self.server_action_loader_modules();
13461373

13471374
let module_graph = this.app_project.app_module_graph(
13481375
*rsc_entry,
1349-
server_action_loader,
1376+
server_action_loader_modules,
13501377
// We only need the client runtime entries for pages not for Route Handlers
13511378
if is_app_page {
13521379
this.app_project.client_runtime_entries()
@@ -1547,7 +1574,7 @@ impl AppEndpoint {
15471574
if emit_rsc_manifests {
15481575
server_assets.insert(
15491576
create_server_actions_manifest(
1550-
self.server_action_loader_module(),
1577+
self.server_action_loader_modules(),
15511578
node_root.clone(),
15521579
app_entry.original_name.clone(),
15531580
runtime,
@@ -1864,24 +1891,29 @@ impl AppEndpoint {
18641891
let project = this.app_project.project();
18651892
let app_entry = self.app_endpoint_entry().await?;
18661893
let runtime = app_entry.config.await?.runtime.unwrap_or_default();
1867-
let server_action_loader = self.server_action_loader_module().to_resolved().await?;
1894+
let server_action_loaders = self.server_action_loader_modules().await?;
18681895

18691896
let chunking_context = project.runtime_chunking_context(process_client_assets, runtime);
18701897

1898+
let entry_chunk_group = ChunkGroup::Entry(
1899+
server_action_loaders
1900+
.iter()
1901+
.copied()
1902+
.chain(std::iter::once(app_entry.rsc_entry))
1903+
.collect(),
1904+
);
1905+
18711906
Ok(match runtime {
18721907
NextRuntime::Edge => chunking_context.evaluated_chunk_group_assets(
18731908
app_entry.rsc_entry.ident(),
1874-
ChunkGroup::Entry(vec![server_action_loader, app_entry.rsc_entry]),
1909+
entry_chunk_group,
18751910
module_graph,
18761911
AvailabilityInfo::root(),
18771912
),
18781913
NextRuntime::NodeJs => {
18791914
async {
18801915
let mut current_chunk_group = ChunkGroupResult::empty_resolved();
18811916

1882-
let entry_chunk_group =
1883-
ChunkGroup::Entry(vec![server_action_loader, app_entry.rsc_entry]);
1884-
18851917
let chunk_group_info = module_graph.chunk_group_info();
18861918

18871919
let client_references = client_references.await?;
@@ -2138,10 +2170,14 @@ impl Endpoint for AppEndpoint {
21382170
async fn entries(self: Vc<Self>) -> Result<Vc<GraphEntries>> {
21392171
let this = self.await?;
21402172
Ok(Vc::cell(vec![
2141-
ChunkGroupEntry::Entry(vec![
2142-
self.server_action_loader_module().to_resolved().await?,
2143-
self.app_endpoint_entry().await?.rsc_entry,
2144-
]),
2173+
ChunkGroupEntry::Entry(
2174+
self.server_action_loader_modules()
2175+
.await?
2176+
.iter()
2177+
.copied()
2178+
.chain(std::iter::once(self.app_endpoint_entry().await?.rsc_entry))
2179+
.collect(),
2180+
),
21452181
ChunkGroupEntry::Entry(
21462182
this.app_project
21472183
.client_runtime_entries()
@@ -2158,12 +2194,12 @@ impl Endpoint for AppEndpoint {
21582194
async fn module_graphs(self: Vc<Self>) -> Result<Vc<ModuleGraphs>> {
21592195
let this = self.await?;
21602196
let app_entry = self.app_endpoint_entry().await?;
2161-
let server_action_loader = self.server_action_loader_module();
2197+
let server_action_loader_modules = self.server_action_loader_modules();
21622198
let module_graph = this
21632199
.app_project
21642200
.app_module_graph(
21652201
*app_entry.rsc_entry,
2166-
server_action_loader,
2202+
server_action_loader_modules,
21672203
this.app_project.client_runtime_entries(),
21682204
matches!(this.ty, AppEndpointType::Page { .. }),
21692205
)

crates/next-api/src/server_actions.rs

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{Context, Result};
1+
use anyhow::{Context, Result, bail};
22
use bincode::{Decode, Encode};
33
use next_core::{
44
next_manifests::{ActionLayer, ActionManifestWorkerEntry, ServerReferenceManifest},
@@ -10,7 +10,10 @@ use turbo_tasks_fs::{self, File, FileContent, FileSystem, FileSystemPath, Virtua
1010
use turbopack_core::{
1111
self,
1212
asset::AssetContent,
13-
chunk::{AsyncModuleInfo, ChunkItem, ChunkableModule, ChunkingContext, EvaluatableAsset},
13+
chunk::{
14+
AsyncModuleInfo, ChunkItem, ChunkableModule, ChunkingContext, ChunkingType,
15+
EvaluatableAsset,
16+
},
1417
emit_collect::{CollectingModule, EmittedModuleReference},
1518
ident::AssetIdent,
1619
module::{Module, ModuleSideEffects, Modules},
@@ -31,14 +34,14 @@ use turbopack_ecmascript::chunk::{
3134
/// loader.
3235
#[turbo_tasks::function]
3336
pub(crate) async fn create_server_actions_manifest(
34-
server_action_loader: Vc<Box<dyn Module>>,
37+
server_action_loader_modules: Vc<Modules>,
3538
node_root: FileSystemPath,
3639
page_name: RcStr,
3740
runtime: NextRuntime,
3841
module_graph: Vc<ModuleGraph>,
3942
chunking_context: Vc<Box<dyn ChunkingContext>>,
4043
) -> Vc<Box<dyn OutputAsset>> {
41-
let actions = collect_actions(server_action_loader, module_graph);
44+
let actions = collect_actions(server_action_loader_modules, module_graph);
4245
build_manifest(
4346
node_root,
4447
page_name,
@@ -51,29 +54,36 @@ pub(crate) async fn create_server_actions_manifest(
5154

5255
#[turbo_tasks::function]
5356
async fn collect_actions(
54-
server_action_loader: ResolvedVc<Box<dyn Module>>,
57+
server_action_loader_modules: Vc<Modules>,
5558
module_graph: Vc<ModuleGraph>,
5659
) -> Result<Vc<AllActions>> {
5760
// This mirrors what the ServerActionCollectModule ends up chunking into the chunk.
5861
let collected_modules = module_graph.collected_modules().await?;
59-
// This can be none if there are no server actions
60-
let actions =
61-
collected_modules
62-
.collected_references
63-
.iter()
64-
.find_map(|((entry, loader), actions)| {
65-
if *entry == server_action_loader && *loader == server_action_loader {
66-
Some(actions)
67-
} else {
68-
None
69-
}
70-
});
62+
let server_action_loader_modules = server_action_loader_modules.await?;
63+
assert_eq!(server_action_loader_modules.len(), 2);
64+
65+
let actions = collected_modules
66+
.collected_references
67+
.iter()
68+
.filter(|((_entry_modules, loader), _)| {
69+
// No need to check entry_modules. Each page (ChunkGroup::Entry) has its own loader
70+
// module anyway.
71+
72+
// server_action_loader_modules contains only 2 modules, so converting that into a
73+
// hashset for quicker lookup is not necessary.
74+
server_action_loader_modules.contains(loader)
75+
})
76+
// Early stop the search. There can only ever be two matches
77+
.take(2)
78+
.flat_map(|(_, actions)| actions.iter());
7179

7280
Ok(Vc::cell(
7381
actions
74-
.into_iter()
75-
.flatten()
7682
.map(async |(data, module, _)| {
83+
let namespace = match &data.chunking_type {
84+
ChunkingType::Collected { merge_tag, .. } => merge_tag,
85+
_ => bail!("unexpected chunking type for collected reference"),
86+
};
7787
let data =
7888
ResolvedVc::try_sidecast::<Box<dyn EmittedModuleReference>>(data.reference)
7989
.context(
@@ -92,7 +102,13 @@ async fn collect_actions(
92102
Ok((
93103
hash.to_string(),
94104
(
95-
ActionLayer::ActionBrowser, // TODO
105+
match namespace.as_str() {
106+
"next/server-actions" => ActionLayer::Rsc,
107+
"next/server-actions/edge" | "next/server-actions/node" => {
108+
ActionLayer::ActionBrowser
109+
}
110+
_ => bail!("unexpected namespace {namespace} for collected reference"),
111+
},
96112
ActionMeta {
97113
name: name.to_string(),
98114
source_path: "".to_string(), // TODO

crates/next-custom-transforms/src/transforms/server_actions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3276,13 +3276,13 @@ fn emit_server_action(
32763276
} else {
32773277
vec![
32783278
quote!(
3279-
"$emit($req, {namespace:'next/server-actions', data: $data, with: { 'turbopack-transition': 'next-rsc' }});" as Stmt,
3279+
"$emit($req, {namespace:'next/server-actions/node', data: $data, with: { 'turbopack-transition': 'next-rsc' }});" as Stmt,
32803280
emit = emit.clone(),
32813281
req: Expr = req.clone(),
32823282
data: Expr = data.clone()
32833283
),
32843284
quote!(
3285-
"$emit($req, {namespace:'next/server-actions', data: $data, with: { 'turbopack-transition': 'next-edge-rsc' }});" as Stmt,
3285+
"$emit($req, {namespace:'next/server-actions/edge', data: $data, with: { 'turbopack-transition': 'next-edge-rsc' }});" as Stmt,
32863286
emit = emit,
32873287
req: Expr = req,
32883288
data: Expr = data,

crates/next-custom-transforms/tests/fixture/server-actions/client-graph/turbopack/1/output.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/next-custom-transforms/tests/fixture/server-actions/client-graph/turbopack/2/output.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { createServerReference, callServer, findSourceMapURL } from "private-nex
22
const $$RSC_SERVER_ACTION_0 = /*#__PURE__*/ createServerReference("00ab21efdafbe611287bc25c0462b1e0510d13e48b", callServer, void 0, findSourceMapURL, "foo");
33
export { $$RSC_SERVER_ACTION_0 as foo };
44
__turbopack_emit__("./item.js", {
5-
namespace: 'next/server-actions',
5+
namespace: 'next/server-actions/node',
66
data: "00ab21efdafbe611287bc25c0462b1e0510d13e48b|foo",
77
with: {
88
'turbopack-transition': 'next-rsc'
99
}
1010
});
1111
__turbopack_emit__("./item.js", {
12-
namespace: 'next/server-actions',
12+
namespace: 'next/server-actions/edge',
1313
data: "00ab21efdafbe611287bc25c0462b1e0510d13e48b|foo",
1414
with: {
1515
'turbopack-transition': 'next-edge-rsc'

crates/next-custom-transforms/tests/fixture/server-actions/client-graph/turbopack/3/output.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { createServerReference, callServer, findSourceMapURL } from "private-next-rsc-action-client-wrapper";
22
export default /*#__PURE__*/ createServerReference("00c18c215a6b7cdc64bf709f3a714ffdef1bf9651d", callServer, void 0, findSourceMapURL, "default");
33
__turbopack_emit__("./item.js", {
4-
namespace: 'next/server-actions',
4+
namespace: 'next/server-actions/node',
55
data: "00c18c215a6b7cdc64bf709f3a714ffdef1bf9651d|default",
66
with: {
77
'turbopack-transition': 'next-rsc'
88
}
99
});
1010
__turbopack_emit__("./item.js", {
11-
namespace: 'next/server-actions',
11+
namespace: 'next/server-actions/edge',
1212
data: "00c18c215a6b7cdc64bf709f3a714ffdef1bf9651d|default",
1313
with: {
1414
'turbopack-transition': 'next-edge-rsc'

0 commit comments

Comments
 (0)