Skip to content

Commit 2266fc4

Browse files
fix(mf): align manifest shared names with runtime keys
1 parent 6c6388e commit 2266fc4

File tree

8 files changed

+74
-14
lines changed

8 files changed

+74
-14
lines changed

crates/node_binding/napi-binding.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,7 @@ export interface RawManifestExposeOption {
25312531

25322532
export interface RawManifestSharedOption {
25332533
name: string
2534+
shareKey: string
25342535
version?: string
25352536
requiredVersion?: string
25362537
singleton?: boolean

crates/rspack_binding_api/src/raw_options/raw_builtins/raw_mf.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ pub struct RawManifestExposeOption {
390390
#[napi(object)]
391391
pub struct RawManifestSharedOption {
392392
pub name: String,
393+
pub share_key: String,
393394
pub version: Option<String>,
394395
pub required_version: Option<String>,
395396
pub singleton: Option<bool>,
@@ -458,6 +459,7 @@ impl From<RawModuleFederationManifestPluginOptions> for ModuleFederationManifest
458459
.into_iter()
459460
.map(|shared| ManifestSharedOption {
460461
name: shared.name,
462+
share_key: shared.share_key,
461463
version: shared.version,
462464
required_version: shared.required_version,
463465
singleton: shared.singleton,

crates/rspack_plugin_mf/src/manifest/data.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub struct StatsExpose {
4747
pub struct StatsShared {
4848
pub id: String,
4949
pub name: String,
50+
#[serde(rename = "shareKey")]
51+
pub share_key: String,
5052
pub version: String,
5153
#[serde(default)]
5254
pub requiredVersion: Option<String>,
@@ -146,6 +148,8 @@ pub struct ManifestExpose {
146148
pub struct ManifestShared {
147149
pub id: String,
148150
pub name: String,
151+
#[serde(rename = "shareKey")]
152+
pub share_key: String,
149153
pub version: String,
150154
#[serde(default)]
151155
pub requiredVersion: Option<String>,

crates/rspack_plugin_mf/src/manifest/mod.rs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,37 @@ fn rsc_module_type_priority(module_type: &str) -> u8 {
6868
}
6969
}
7070

71+
fn resolve_manifest_shared_option<'a>(
72+
shared_options: &'a [ManifestSharedOption],
73+
concrete_share_key: &str,
74+
) -> (String, Option<&'a ManifestSharedOption>) {
75+
if let Some(shared) = shared_options
76+
.iter()
77+
.find(|shared| shared.share_key == concrete_share_key)
78+
{
79+
return (shared.name.clone(), Some(shared));
80+
}
81+
82+
let prefix_match = shared_options
83+
.iter()
84+
.filter(|shared| {
85+
shared.share_key.ends_with('/') && concrete_share_key.starts_with(&shared.share_key)
86+
})
87+
.max_by_key(|shared| shared.share_key.len());
88+
89+
if let Some(shared) = prefix_match {
90+
let remainder = &concrete_share_key[shared.share_key.len()..];
91+
let manifest_name = if shared.name.ends_with('/') {
92+
format!("{}{}", shared.name, remainder)
93+
} else {
94+
shared.name.clone()
95+
};
96+
return (manifest_name, Some(shared));
97+
}
98+
99+
(concrete_share_key.to_string(), None)
100+
}
101+
71102
fn collect_rsc_candidates_for_module(
72103
compilation: &Compilation,
73104
module_identifier: &ModuleIdentifier,
@@ -318,6 +349,7 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
318349
.map(|shared| StatsShared {
319350
id: compose_id_with_separator(&container_name, &shared.name),
320351
name: shared.name.clone(),
352+
share_key: shared.share_key.clone(),
321353
version: shared.version.clone().unwrap_or_default(),
322354
requiredVersion: shared.required_version.clone(),
323355
// default singleton to true when not provided by user
@@ -461,12 +493,15 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
461493

462494
if matches!(module_type, ModuleType::ProvideShared) {
463495
if let Some((pkg, ver)) = parse_provide_shared_identifier(&identifier) {
464-
let entry = ensure_shared_entry(&mut shared_map, &container_name, &pkg);
496+
let (manifest_name, matched_shared) =
497+
resolve_manifest_shared_option(&self.options.shared, &pkg);
498+
let entry = ensure_shared_entry(&mut shared_map, &container_name, &manifest_name, &pkg);
465499
if entry.version.is_empty() {
466500
entry.version = ver;
467501
}
502+
entry.share_key = pkg.clone();
468503
// overlay user-configured shared options (singleton/requiredVersion/version)
469-
if let Some(opt) = self.options.shared.iter().find(|s| s.name == pkg) {
504+
if let Some(opt) = matched_shared {
470505
if let Some(singleton) = opt.singleton {
471506
entry.singleton = Some(singleton);
472507
}
@@ -477,7 +512,9 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
477512
entry.version = cfg_ver;
478513
}
479514
}
480-
let targets = shared_module_targets.entry(pkg.clone()).or_default();
515+
let targets = shared_module_targets
516+
.entry(manifest_name.clone())
517+
.or_default();
481518
for connection in module_graph.get_outgoing_connections(&module_identifier) {
482519
let referenced = *connection.module_identifier();
483520
if should_collect_module(&referenced) {
@@ -507,10 +544,12 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
507544
else {
508545
continue;
509546
};
510-
let pkg = consume_shared_module.share_key().to_string();
511-
if pkg.is_empty() {
547+
let share_key = consume_shared_module.share_key().to_string();
548+
if share_key.is_empty() {
512549
continue;
513550
}
551+
let (pkg, matched_shared) =
552+
resolve_manifest_shared_option(&self.options.shared, &share_key);
514553
let required = consume_shared_module
515554
.required_version()
516555
.map(ToString::to_string);
@@ -529,12 +568,13 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
529568
.entry(pkg.clone())
530569
.or_default()
531570
.extend(target_ids.into_iter());
532-
let entry = ensure_shared_entry(&mut shared_map, &container_name, &pkg);
571+
let entry = ensure_shared_entry(&mut shared_map, &container_name, &pkg, &share_key);
572+
entry.share_key = share_key.clone();
533573
if entry.requiredVersion.is_none() && required.is_some() {
534574
entry.requiredVersion = required;
535575
}
536576
// overlay user-configured shared options
537-
if let Some(opt) = self.options.shared.iter().find(|s| s.name == pkg) {
577+
if let Some(opt) = matched_shared {
538578
if let Some(singleton) = opt.singleton {
539579
entry.singleton = Some(singleton);
540580
}
@@ -630,8 +670,13 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
630670
let Some(module_ids) = shared_module_targets.get(pkg) else {
631671
continue;
632672
};
673+
let lookup = if shared_entry.share_key.is_empty() {
674+
pkg.clone()
675+
} else {
676+
shared_entry.share_key.clone()
677+
};
633678
shared_entry.rsc =
634-
build_rsc_reference_meta_from_modules(compilation, pkg.clone(), module_ids.iter().copied());
679+
build_rsc_reference_meta_from_modules(compilation, lookup, module_ids.iter().copied());
635680
}
636681

637682
for (expose_file_key, expose) in exposes_map.iter_mut() {
@@ -842,6 +887,7 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
842887
.map(|s| ManifestShared {
843888
id: s.id,
844889
name: s.name,
890+
share_key: s.share_key,
845891
version: s.version,
846892
requiredVersion: s.requiredVersion,
847893
singleton: s.singleton,

crates/rspack_plugin_mf/src/manifest/options.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct ManifestExposeOption {
1717
#[derive(Debug, Clone)]
1818
pub struct ManifestSharedOption {
1919
pub name: String,
20+
pub share_key: String,
2021
pub version: Option<String>,
2122
pub required_version: Option<String>,
2223
pub singleton: Option<bool>,

crates/rspack_plugin_mf/src/manifest/utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,14 @@ pub fn ensure_shared_entry<'a>(
171171
shared_map: &'a mut HashMap<String, StatsShared>,
172172
container_name: &str,
173173
pkg: &str,
174+
share_key: &str,
174175
) -> &'a mut StatsShared {
175176
shared_map
176177
.entry(pkg.to_string())
177178
.or_insert_with(|| StatsShared {
178179
id: compose_id_with_separator(container_name, pkg),
179180
name: pkg.to_string(),
181+
share_key: share_key.to_string(),
180182
version: String::new(),
181183
requiredVersion: None,
182184
// default singleton to true

packages/rspack/src/container/ModuleFederationManifestPlugin.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export type ManifestExposeOption = {
116116

117117
export type ManifestSharedOption = {
118118
name: string;
119+
shareKey: string;
119120
version?: string;
120121
requiredVersion?: string;
121122
singleton?: boolean;
@@ -250,15 +251,16 @@ function collectManifestShared(
250251
(item) => item,
251252
);
252253
const result = parsed.map(([key, config]) => {
253-
const name = config.shareKey || key;
254+
const shareKey = config.shareKey || key;
254255
const version =
255256
typeof config.version === 'string' ? config.version : undefined;
256257
const requiredVersion =
257258
typeof config.requiredVersion === 'string'
258259
? config.requiredVersion
259260
: undefined;
260261
return {
261-
name,
262+
name: key,
263+
shareKey,
262264
version,
263265
requiredVersion,
264266
singleton: config.singleton,

tests/rspack-test/configCases/container-1-5/manifest-rsc-references/index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ const manifestPath = path.join(__dirname, "mf-manifest.json");
66
const stats = JSON.parse(fs.readFileSync(statsPath, "utf-8"));
77
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
88

9-
it("should capture RSC references for shared modules by shareKey", () => {
10-
const shared = stats.shared.find(item => item.name === "rsc-shared-key");
9+
it("should capture RSC references for shared modules by package key", () => {
10+
const shared = stats.shared.find(item => item.name === "shared-rsc");
1111
expect(shared).toBeDefined();
12+
expect(shared.shareKey).toBe("rsc-shared-key");
1213
expect(shared.rsc).toBeDefined();
13-
expect(shared.rsc.lookup).toBe("rsc-shared-key");
14+
expect(shared.rsc.lookup).toBe(shared.shareKey);
1415
expect(shared.rsc.moduleType).toBe("client");
1516
expect(shared.rsc.clientReferences).toEqual(
1617
expect.arrayContaining(["SharedClientComponent", "sharedAction", "sharedValue"])
@@ -44,7 +45,8 @@ it("should persist RSC metadata in mf-manifest.json", () => {
4445
expect(manifest.shared).toEqual(
4546
expect.arrayContaining([
4647
expect.objectContaining({
47-
name: "rsc-shared-key",
48+
name: "shared-rsc",
49+
shareKey: "rsc-shared-key",
4850
rsc: expect.objectContaining({
4951
lookup: "rsc-shared-key"
5052
})

0 commit comments

Comments
 (0)