Skip to content

Commit c7b6df2

Browse files
committed
fix: buildInfo rsc for builtin flight client entry plugin
1 parent 04c9a04 commit c7b6df2

File tree

3 files changed

+66
-101
lines changed

3 files changed

+66
-101
lines changed
Lines changed: 13 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use rspack_core::Module;
2+
use serde::Deserialize;
23

3-
const CLIENT_MODULE_LABEL: &str =
4-
r"/\* __next_internal_client_entry_do_not_use__ ([^ ]*) (cjs|auto) \*/";
5-
const ACTION_MODULE_LABEL: &str = r"/\* __next_internal_action_entry_do_not_use__ (\{[^}]+\}) \*/";
4+
const RSPACK_RSC_MODULE_INFORMATION: &str =
5+
r"/\* __rspack_internal_rsc_module_information_do_not_use__ (\{[^}]+\}) \*/";
66

77
const CLIENT_DIRECTIVE: &str = "use client";
88
const SERVER_ACTION_DIRECTIVE: &str = "use server";
@@ -18,80 +18,27 @@ pub struct RSCModuleTypes {
1818
pub server: RSCModuleType,
1919
}
2020

21-
#[derive(Default)]
21+
#[derive(Debug, Default, Deserialize)]
22+
#[serde(rename_all = "camelCase")]
2223
pub struct RSCMeta {
23-
pub r#type: RSCModuleType,
24+
pub r#type: String, // RSCModuleType
2425
pub actions: Option<Vec<String>>,
2526
pub action_ids: Option<std::collections::HashMap<String, String>>,
2627
pub client_refs: Option<Vec<String>>,
2728
pub client_entry_type: Option<String>,
2829
pub is_client_ref: bool,
2930
}
3031

31-
fn get_rsc_module_information(source: &str, is_react_server_layer: bool) -> RSCMeta {
32-
let actions_json = regex::Regex::new(ACTION_MODULE_LABEL)
32+
fn get_rsc_module_information(source: &str) -> Option<RSCMeta> {
33+
regex::Regex::new(RSPACK_RSC_MODULE_INFORMATION)
3334
.unwrap()
3435
.captures(source)
35-
.and_then(|caps| caps.get(1).map(|m| m.as_str()));
36-
let parsed_actions_meta = actions_json
37-
.map(|json| serde_json::from_str::<std::collections::HashMap<String, String>>(json).unwrap());
38-
let actions = parsed_actions_meta
39-
.as_ref()
40-
.map(|meta| meta.values().cloned().collect());
41-
42-
let client_info_match = regex::Regex::new(CLIENT_MODULE_LABEL)
43-
.unwrap()
44-
.captures(source);
45-
let is_client_ref = client_info_match.is_some();
46-
47-
if !is_react_server_layer {
48-
return RSCMeta {
49-
r#type: RSC_MODULE_TYPES.client,
50-
actions,
51-
action_ids: parsed_actions_meta,
52-
client_refs: None,
53-
client_entry_type: None,
54-
is_client_ref,
55-
};
56-
}
57-
58-
let client_refs_string = client_info_match
59-
.as_ref()
60-
.and_then(|caps| caps.get(1).map(|m| m.as_str()));
61-
let client_refs = client_refs_string.map(|s| s.split(',').map(String::from).collect());
62-
let client_entry_type = client_info_match
63-
.as_ref()
64-
.and_then(|caps| caps.get(2).map(|m| m.as_str().to_string()));
65-
66-
let r#type = if client_info_match.is_some() {
67-
RSC_MODULE_TYPES.client
68-
} else {
69-
RSC_MODULE_TYPES.server
70-
};
71-
72-
RSCMeta {
73-
r#type,
74-
actions,
75-
action_ids: parsed_actions_meta,
76-
client_refs,
77-
client_entry_type,
78-
is_client_ref,
79-
}
80-
}
81-
82-
pub struct BuildInfo {
83-
pub rsc: RSCMeta,
36+
.and_then(|caps| caps.get(1).map(|m| m.as_str()))
37+
.and_then(|info| serde_json::from_str(info).unwrap())
8438
}
8539

86-
pub fn get_module_build_info(module: &dyn Module) -> BuildInfo {
87-
let is_react_server_layer = module
88-
.get_layer()
89-
.is_some_and(|layer| layer == "react-server");
90-
91-
let rsc = module
40+
pub fn get_module_rsc_information(module: &dyn Module) -> Option<RSCMeta> {
41+
module
9242
.original_source()
93-
.map(|s| get_rsc_module_information(s.source().as_ref(), is_react_server_layer))
94-
.unwrap_or_default();
95-
96-
BuildInfo { rsc }
43+
.and_then(|s| get_rsc_module_information(s.source().as_ref()))
9744
}

crates/rspack_plugin_next_flight_client_entry/src/lib.rs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![feature(let_chains)]
2+
13
mod constants;
24
mod for_each_entry_module;
35
mod get_module_build_info;
@@ -20,7 +22,7 @@ use constants::{
2022
use derive_more::Debug;
2123
use for_each_entry_module::for_each_entry_module;
2224
use futures::future::BoxFuture;
23-
use get_module_build_info::get_module_build_info;
25+
use get_module_build_info::get_module_rsc_information;
2426
use is_metadata_route::is_metadata_route;
2527
use itertools::Itertools;
2628
use loader_util::{get_actions_from_build_info, is_client_component_entry_module, is_css_mod};
@@ -289,26 +291,31 @@ fn get_module_resource(module: &dyn Module) -> String {
289291
}
290292

291293
pub fn get_assumed_source_type(module: &dyn Module, source_type: String) -> String {
292-
let build_info = get_module_build_info(module);
293-
let detected_client_entry_type = build_info.rsc.client_entry_type;
294-
let client_refs = build_info.rsc.client_refs.unwrap_or(vec![]);
294+
let rsc = get_module_rsc_information(module);
295+
let detected_client_entry_type = rsc
296+
.as_ref()
297+
.and_then(|rsc| rsc.client_entry_type.as_deref());
298+
let client_refs: &[String] = rsc
299+
.as_ref()
300+
.and_then(|rsc| rsc.client_refs.as_ref().map(|r| r.as_slice()))
301+
.unwrap_or_default();
295302

296303
// It's tricky to detect the type of a client boundary, but we should always
297304
// use the `module` type when we can, to support `export *` and `export from`
298305
// syntax in other modules that import this client boundary.
299306

300307
if source_type == "auto" {
301-
if detected_client_entry_type == Some("auto".to_string()) {
308+
if detected_client_entry_type == Some("auto") {
302309
if client_refs.is_empty() {
303310
// If there's zero export detected in the client boundary, and it's the
304311
// `auto` type, we can safely assume it's a CJS module because it doesn't
305312
// have ESM exports.
306313
return "commonjs".to_string();
307-
} else if !client_refs.contains(&"*".to_string()) {
314+
} else if !client_refs.iter().any(|e| e == "*") {
308315
// Otherwise, we assume it's an ESM module.
309316
return "module".to_string();
310317
}
311-
} else if detected_client_entry_type == Some("cjs".to_string()) {
318+
} else if detected_client_entry_type == Some("cjs") {
312319
return "commonjs".to_string();
313320
}
314321
}
@@ -323,9 +330,9 @@ fn add_client_import(
323330
imported_identifiers: &[String],
324331
is_first_visit_module: bool,
325332
) {
326-
let build_info = get_module_build_info(module);
327-
let client_entry_type = build_info.rsc.client_entry_type;
328-
let is_cjs_module = client_entry_type == Some("cjs".to_string());
333+
let rsc = get_module_rsc_information(module);
334+
let client_entry_type = rsc.and_then(|rsc| rsc.client_entry_type);
335+
let is_cjs_module = matches!(client_entry_type, Some(t) if t == "cjs");
329336
let assumed_source_type = get_assumed_source_type(
330337
module,
331338
if is_cjs_module {
@@ -1090,7 +1097,7 @@ impl FlightClientEntryPlugin {
10901097
add_client_entry_and_ssr_modules_list.push(injected);
10911098
}
10921099

1093-
if is_app_route_route(name.as_str()) {
1100+
if !is_app_route_route(name.as_str()) {
10941101
// Create internal app
10951102
add_client_entry_and_ssr_modules_list.push(self.inject_client_entry_and_ssr_modules(
10961103
compilation,
@@ -1450,7 +1457,10 @@ async fn after_emit(&self, compilation: &mut Compilation) -> Result<()> {
14501457
}
14511458
}
14521459
}
1453-
1460+
if mod_resource.contains("app/style.css") {
1461+
dbg!(module.get_layer());
1462+
dbg!(module.identifier());
1463+
}
14541464
if module.get_layer().map(|layer| layer.as_str())
14551465
!= Some(WEBPACK_LAYERS.server_side_rendering)
14561466
{
@@ -1500,6 +1510,18 @@ async fn after_emit(&self, compilation: &mut Compilation) -> Result<()> {
15001510
ChunkGraph::get_module_id(&compilation.module_ids_artifact, *module_identifier)
15011511
{
15021512
record_module(module_id, module_identifier);
1513+
1514+
if let Some(module) = module_graph.module_by_identifier(module_identifier)
1515+
&& let Some(module) = module.as_concatenated_module()
1516+
{
1517+
for m in module.get_modules() {
1518+
if let Some(module_id) =
1519+
ChunkGraph::get_module_id(&compilation.module_ids_artifact, m.id)
1520+
{
1521+
record_module(module_id, &m.id);
1522+
}
1523+
}
1524+
}
15031525
}
15041526
}
15051527
}

crates/rspack_plugin_next_flight_client_entry/src/loader_util.rs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,33 @@ use lazy_regex::Lazy;
44
use regex::Regex;
55
use rspack_core::Module;
66

7-
use crate::get_module_build_info::{get_module_build_info, RSC_MODULE_TYPES};
7+
use crate::get_module_build_info::{get_module_rsc_information, RSC_MODULE_TYPES};
88

99
// Gives { id: name } record of actions from the build info.
1010
pub fn get_actions_from_build_info(module: &dyn Module) -> Option<HashMap<String, String>> {
11-
let build_info = get_module_build_info(module);
12-
build_info.rsc.action_ids
11+
let rsc = get_module_rsc_information(module)?;
12+
rsc.action_ids
1313
}
1414

1515
pub static REGEX_CSS: Lazy<Regex> = Lazy::new(|| Regex::new(r"\.(css|scss|sass)(\?.*)?$").unwrap());
1616

1717
// This function checks if a module is able to emit CSS resources. You should
1818
// never only rely on a single regex to do that.
1919
pub fn is_css_mod(module: &dyn Module) -> bool {
20+
if module.module_type().as_str() == "css/mini-extract" {
21+
return true;
22+
}
2023
let Some(module) = module.as_normal_module() else {
2124
return false;
2225
};
23-
24-
module.module_type().as_str() == "css/mini-extract"
25-
|| (REGEX_CSS.is_match(&module.resource_resolved_data().resource))
26-
27-
// TODO: rspack not support get loader request
28-
// || module.loaders().iter().any(|loader| {
29-
// loader.loader.contains("next-style-loader/index.js")
30-
// || (std::env::var("NEXT_RSPACK").is_ok()
31-
// && loader
32-
// .loader
33-
// .contains("rspack.CssExtractRspackPlugin.loader"))
34-
// || loader.loader.contains("mini-css-extract-plugin/loader.js")
35-
// || loader
36-
// .loader
37-
// .contains("@vanilla-extract/webpack-plugin/loader/")
38-
// })
26+
REGEX_CSS.is_match(&module.resource_resolved_data().resource)
27+
|| module.loaders().iter().any(|loader| {
28+
let loader_ident = loader.identifier();
29+
loader_ident.contains("next-style-loader/index.js")
30+
|| loader_ident.contains("rspack.CssExtractRspackPlugin.loader")
31+
|| loader_ident.contains("mini-css-extract-plugin/loader.js")
32+
|| loader_ident.contains("@vanilla-extract/webpack-plugin/loader/")
33+
})
3934
}
4035

4136
pub static IMAGE_REGEX: Lazy<Regex> = Lazy::new(|| {
@@ -44,8 +39,8 @@ pub static IMAGE_REGEX: Lazy<Regex> = Lazy::new(|| {
4439
});
4540

4641
pub fn is_client_component_entry_module(module: &dyn Module) -> bool {
47-
let build_info = get_module_build_info(module);
48-
let has_client_directive = build_info.rsc.is_client_ref;
42+
let rsc = get_module_rsc_information(module);
43+
let has_client_directive = matches!(rsc, Some(rsc) if rsc.is_client_ref);
4944
let is_action_layer_entry = is_action_client_layer_module(module);
5045
let is_image = if let Some(module) = module.as_normal_module() {
5146
IMAGE_REGEX.is_match(&module.resource_resolved_data().resource)
@@ -57,6 +52,7 @@ pub fn is_client_component_entry_module(module: &dyn Module) -> bool {
5752

5853
// Determine if the whole module is client action, 'use server' in nested closure in the client module
5954
fn is_action_client_layer_module(module: &dyn Module) -> bool {
60-
let build_info = get_module_build_info(module);
61-
build_info.rsc.actions.is_some() && build_info.rsc.r#type == RSC_MODULE_TYPES.client
55+
let rsc = get_module_rsc_information(module);
56+
matches!(&rsc, Some(rsc) if rsc.actions.is_some())
57+
&& matches!(&rsc, Some(rsc) if rsc.r#type == RSC_MODULE_TYPES.client)
6258
}

0 commit comments

Comments
 (0)