Skip to content

Commit 2af3d06

Browse files
authored
Turbopack: split up server actions modules for better treeshaking (#76877)
Closes PACK-4074 We really need to look into getting e2e tests for correct sourcemaps: PACK-4142 Fix Turbopack server action tree shaking by explicitly splitting up that module ```js /* __next_internal_action_entry_do_not_use__ {"00c18c215a6b7cdc64bf709f3a714ffdef1bf9651d":"default","70e10665baac148856374b2789aceb970f66fec33e":"myAction"} */ import { createServerReference, callServer, findSourceMapURL } from "private-next-rsc-action-client-wrapper"; export var foo = /*#__PURE__*/ createServerReference("70e10665baac148856374b2789aceb970f66fec33e", callServer, void 0, findSourceMapURL, "myAction"); export var bar = /*#__PURE__*/ createServerReference("00c18c215a6b7cdc64bf709f3a714ffdef1bf9651d", callServer, void 0, findSourceMapURL, "default"); ``` -> ```js "use turbopack no side effects"; export { foo } from "data:text/javascript,%2F%2A%20__next_internal_action_entry_do_not_use__%20%7B%2200ab21efdafbe611287bc25c0462b1e0510d13e48b%22%3A%22foo%22%7D%20%2A%2F%22use%20turbopack%20no%20side%20effects%22%3Bimport%7BcreateServerReference%2CcallServer%2CfindSourceMapURL%7Dfrom%22private-next-rsc-action-client-wrapper%22%3Bexport%20var%20foo%3D%2F%2A%23__PURE__%2A%2FcreateServerReference%28%2200ab21efdafbe611287bc25c0462b1e0510d13e48b%22%2CcallServer%2Cvoid%200%2CfindSourceMapURL%2C%22foo%22%29%3B"; export { bar } from "data:text/javascript,%2F%2A%20__next_internal_action_entry_do_not_use__%20%7B%2200ac840dcaf5e8197cb02b7f3a43c119b7a770b272%22%3A%22bar%22%7D%20%2A%2F%22use%20turbopack%20no%20side%20effects%22%3Bimport%7BcreateServerReference%2CcallServer%2CfindSourceMapURL%7Dfrom%22private-next-rsc-action-client-wrapper%22%3Bexport%20var%20bar%3D%2F%2A%23__PURE__%2A%2FcreateServerReference%28%2200ac840dcaf5e8197cb02b7f3a43c119b7a770b272%22%2CcallServer%2Cvoid%200%2CfindSourceMapURL%2C%22bar%22%29%3B"; ```` - [x] Keep [sourcemaps](https://github.com/vercel/next.js/blob/canary/test/development/app-dir/source-mapping/README.md#server-actions)
1 parent d3a2971 commit 2af3d06

File tree

32 files changed

+473
-130
lines changed

32 files changed

+473
-130
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/napi/src/next_api/project.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ pub async fn get_source_map_rope(
12871287
}
12881288

12891289
if map.await?.is_none() {
1290-
bail!("chunk/module is missing a sourcemap");
1290+
bail!("chunk/module '{}' is missing a sourcemap", file_path);
12911291
}
12921292

12931293
Ok(Some(map))

crates/next-api/src/module_graph.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,11 @@ impl ServerActionsGraph {
225225
let actions = data
226226
.iter()
227227
.map(|(module, (layer, actions))| async move {
228+
let actions = actions.await?;
228229
actions
229-
.await?
230+
.actions
230231
.iter()
231-
.map(|(hash, name)| async move {
232+
.map(async |(hash, name)| {
232233
Ok((
233234
hash.to_string(),
234235
(
@@ -237,7 +238,13 @@ impl ServerActionsGraph {
237238
if *layer == ActionLayer::Rsc {
238239
*module
239240
} else {
240-
to_rsc_context(**module, rsc_asset_context).await?
241+
to_rsc_context(
242+
**module,
243+
&actions.entry_path,
244+
&actions.entry_query,
245+
rsc_asset_context,
246+
)
247+
.await?
241248
},
242249
),
243250
))

crates/next-api/src/server_actions.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,18 @@ async fn build_manifest(
203203
/// The ActionBrowser layer's module is in the Client context, and we need to
204204
/// bring it into the RSC context.
205205
pub async fn to_rsc_context(
206-
module: Vc<Box<dyn Module>>,
206+
client_module: Vc<Box<dyn Module>>,
207+
entry_path: &str,
208+
entry_query: &str,
207209
asset_context: Vc<Box<dyn AssetContext>>,
208210
) -> Result<ResolvedVc<Box<dyn Module>>> {
209-
let source = FileSource::new_with_query(module.ident().path(), module.ident().query());
211+
// TODO a cleaner solution would something similar to the EcmascriptClientReferenceModule, as
212+
// opposed to the following hack to construct the RSC module corresponding to this client
213+
// module.
214+
let source = FileSource::new_with_query(
215+
client_module.ident().path().root().join(entry_path.into()),
216+
Vc::cell(entry_query.into()),
217+
);
210218
let module = asset_context
211219
.process(
212220
Vc::upcast(source),
@@ -227,7 +235,7 @@ pub async fn to_rsc_context(
227235
pub fn parse_server_actions(
228236
program: &Program,
229237
comments: &dyn Comments,
230-
) -> Option<BTreeMap<String, String>> {
238+
) -> Option<(BTreeMap<String, String>, String, String)> {
231239
let byte_pos = match program {
232240
Program::Module(m) => m.span.lo,
233241
Program::Script(s) => s.span.lo,
@@ -273,7 +281,8 @@ async fn parse_actions(module: Vc<Box<dyn Module>>) -> Result<Vc<OptionActionMap
273281
return Ok(Vc::cell(None));
274282
};
275283

276-
let Some(mut actions) = parse_server_actions(original, comments) else {
284+
let Some((mut actions, entry_path, entry_query)) = parse_server_actions(original, comments)
285+
else {
277286
return Ok(Vc::cell(None));
278287
};
279288

@@ -294,7 +303,14 @@ async fn parse_actions(module: Vc<Box<dyn Module>>) -> Result<Vc<OptionActionMap
294303

295304
let mut actions = FxIndexMap::from_iter(actions.into_iter());
296305
actions.sort_keys();
297-
Ok(Vc::cell(Some(ResolvedVc::cell(actions))))
306+
Ok(Vc::cell(Some(
307+
ActionMap {
308+
actions,
309+
entry_path,
310+
entry_query,
311+
}
312+
.resolved_cell(),
313+
)))
298314
}
299315

300316
fn all_export_names(program: &Program) -> Vec<Atom> {
@@ -395,8 +411,13 @@ impl AllActions {
395411
}
396412

397413
/// Maps the hashed action id to the action's exported function name.
398-
#[turbo_tasks::value(transparent)]
399-
pub struct ActionMap(FxIndexMap<String, String>);
414+
#[turbo_tasks::value]
415+
#[derive(Debug)]
416+
pub struct ActionMap {
417+
pub actions: FxIndexMap<String, String>,
418+
pub entry_path: String,
419+
pub entry_query: String,
420+
}
400421

401422
/// An Option wrapper around [ActionMap].
402423
#[turbo_tasks::value(transparent)]

crates/next-core/src/next_shared/transforms/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,16 @@ fn match_js_extension(enable_mdx_rs: bool) -> Vec<RuleCondition> {
8686
RuleCondition::ResourcePathEndsWith(".tsx".to_string()),
8787
RuleCondition::ResourcePathEndsWith(".mjs".to_string()),
8888
RuleCondition::ResourcePathEndsWith(".cjs".to_string()),
89+
RuleCondition::ContentTypeStartsWith("application/javascript".to_string()),
90+
RuleCondition::ContentTypeStartsWith("text/javascript".to_string()),
8991
];
9092

9193
if enable_mdx_rs {
9294
conditions.append(
9395
vec![
9496
RuleCondition::ResourcePathEndsWith(".md".to_string()),
9597
RuleCondition::ResourcePathEndsWith(".mdx".to_string()),
98+
RuleCondition::ContentTypeStartsWith("text/markdown".to_string()),
9699
]
97100
.as_mut(),
98101
);

crates/next-core/src/next_shared/transforms/server_actions.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use anyhow::Result;
22
use async_trait::async_trait;
3-
use next_custom_transforms::transforms::server_actions::{server_actions, Config};
3+
use next_custom_transforms::transforms::server_actions::{
4+
server_actions, Config, ServerActionsMode,
5+
};
46
use swc_core::{common::FileName, ecma::ast::Program};
57
use turbo_rcstr::RcStr;
68
use turbo_tasks::{ResolvedVc, Vc};
@@ -12,7 +14,9 @@ use crate::{mode::NextMode, next_config::CacheKinds};
1214

1315
#[derive(Debug)]
1416
pub enum ActionsTransform {
17+
/// Browser and SSR
1518
Client,
19+
/// RSC Server
1620
Server,
1721
}
1822

@@ -57,6 +61,7 @@ impl CustomTransformer for NextServerActions {
5761
async fn transform(&self, program: &mut Program, ctx: &TransformContext<'_>) -> Result<()> {
5862
let actions = server_actions(
5963
&FileName::Real(ctx.file_path_str.into()),
64+
Some(ctx.query_str.clone()),
6065
Config {
6166
is_react_server_layer: matches!(self.transform, ActionsTransform::Server),
6267
is_development: self.mode.is_development(),
@@ -65,7 +70,9 @@ impl CustomTransformer for NextServerActions {
6570
cache_kinds: self.cache_kinds.owned().await?,
6671
},
6772
ctx.comments.clone(),
73+
ctx.source_map.clone(),
6874
Default::default(),
75+
ServerActionsMode::Turbopack,
6976
);
7077
program.mutate(actions);
7178
Ok(())

crates/next-custom-transforms/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ plugin = [
1414
workspace = true
1515

1616
[dependencies]
17+
base64 = "0.21.0"
1718
chrono = "0.4"
1819
easy-error = "1.0.0"
1920
either = "1"
@@ -38,6 +39,7 @@ swc_core = { workspace = true, features = [
3839
"cached",
3940
"common_concurrent",
4041
"ecma_ast",
42+
"ecma_codegen",
4143
"ecma_loader_lru",
4244
"ecma_loader_node",
4345
"ecma_minifier",
@@ -59,6 +61,7 @@ swc_emotion = { workspace = true }
5961
swc_relay = { workspace = true }
6062
turbopack-ecmascript-plugins = { workspace = true, optional = true }
6163
turbo-rcstr = { workspace = true }
64+
urlencoding = { workspace = true }
6265

6366
react_remove_properties = "0.33.0"
6467
remove_console = "0.34.0"

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

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::{
2727
fonts::next_font_loaders,
2828
lint_codemod_comments::lint_codemod_comments,
2929
react_server_components,
30+
server_actions::ServerActionsMode,
3031
},
3132
};
3233

@@ -323,9 +324,12 @@ where
323324
match &opts.server_actions {
324325
Some(config) => Either::Left(crate::transforms::server_actions::server_actions(
325326
&file.name,
327+
None,
326328
config.clone(),
327329
comments.clone(),
330+
cm.clone(),
328331
use_cache_telemetry_tracker,
332+
ServerActionsMode::Webpack,
329333
)),
330334
None => Either::Right(noop_pass()),
331335
},

0 commit comments

Comments
 (0)