Skip to content

Commit aa284b9

Browse files
authored
feat(mf): recursive search for versions of shared dependencies (#8388)
1 parent b09e6b9 commit aa284b9

File tree

19 files changed

+167
-24
lines changed

19 files changed

+167
-24
lines changed

crates/rspack_plugin_mf/src/sharing/consume_shared_plugin.rs

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::PathBuf;
1+
use std::collections::HashSet;
22
use std::sync::LazyLock;
33
use std::sync::Mutex;
44
use std::{fmt, path::Path, sync::Arc};
@@ -98,19 +98,31 @@ fn resolve_matched_configs(
9898
}
9999
}
100100

101-
async fn get_description_file(mut dir: &Path) -> Option<(PathBuf, serde_json::Value)> {
101+
async fn get_description_file(
102+
mut dir: &Path,
103+
satisfies_description_file_data: Option<impl Fn(Option<serde_json::Value>) -> bool>,
104+
) -> (Option<serde_json::Value>, Option<Vec<String>>) {
102105
let description_filename = "package.json";
106+
let mut checked_file_paths = HashSet::new();
107+
103108
loop {
104109
let description_file = dir.join(description_filename);
105110
if let Ok(data) = tokio::fs::read(&description_file).await
106111
&& let Ok(data) = serde_json::from_slice::<serde_json::Value>(&data)
107112
{
108-
return Some((description_file, data));
113+
if satisfies_description_file_data
114+
.as_ref()
115+
.map_or(false, |f| !f(Some(data.clone())))
116+
{
117+
checked_file_paths.insert(description_file.to_string_lossy().to_string());
118+
} else {
119+
return (Some(data), None);
120+
}
109121
}
110122
if let Some(parent) = dir.parent() {
111123
dir = parent;
112124
} else {
113-
return None;
125+
return (None, Some(checked_file_paths.into_iter().collect()));
114126
}
115127
}
116128
}
@@ -226,29 +238,55 @@ impl ConsumeSharedPlugin {
226238
required_version_warning("Unable to extract the package name from request.");
227239
return None;
228240
};
229-
if let Some(package_name) = package_name
230-
&& let Some((description_path, data)) = get_description_file(context.as_ref()).await
231-
{
232-
if let Some(name) = data.get("name").and_then(|n| n.as_str())
233-
&& name == package_name
234-
{
235-
// Package self-referencing
241+
242+
if let Some(package_name) = package_name {
243+
let (data, checked_description_file_paths) = get_description_file(
244+
context.as_ref(),
245+
Some(|data: Option<serde_json::Value>| {
246+
if let Some(data) = data {
247+
let name_matches = data
248+
.get("name")
249+
.and_then(|n| n.as_str())
250+
.map_or(false, |name| name == package_name);
251+
let version_matches = get_required_version_from_description_file(data, package_name)
252+
.map_or(false, |version| {
253+
matches!(version, ConsumeVersion::Version(_))
254+
});
255+
name_matches || version_matches
256+
} else {
257+
false
258+
}
259+
}),
260+
)
261+
.await;
262+
263+
if let Some(data) = data {
264+
if let Some(name) = data.get("name").and_then(|n| n.as_str())
265+
&& name == package_name
266+
{
267+
// Package self-referencing
268+
return None;
269+
}
270+
return get_required_version_from_description_file(data, package_name);
271+
} else {
272+
if let Some(file_paths) = checked_description_file_paths
273+
&& !file_paths.is_empty()
274+
{
275+
required_version_warning(&format!(
276+
"Unable to find required version for \"{package_name}\" in description file/s\n{}\nIt need to be in dependencies, devDependencies or peerDependencies.",
277+
file_paths.join("\n")
278+
));
279+
} else {
280+
required_version_warning(&format!(
281+
"Unable to find description file in {}",
282+
context.as_str()
283+
));
284+
}
236285
return None;
237286
}
238-
get_required_version_from_description_file(data, package_name).or_else(|| {
239-
required_version_warning(&format!(
240-
"Unable to find required version for \"{package_name}\" in description file ({}). It need to be in dependencies, devDependencies or peerDependencies.",
241-
description_path.display(),
242-
));
243-
None
244-
})
245-
} else {
246-
required_version_warning(&format!(
247-
"Unable to find description file in {}",
248-
context.as_str()
249-
));
250-
None
251287
}
288+
289+
None
252290
}
253291
}
254292

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
it('should provide own dependency', async () => {
2+
expect(await import('lib')).toEqual(
3+
expect.objectContaining({
4+
5+
}),
6+
);
7+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "commonjs"
3+
}

tests/webpack-test/configCases/sharing/share-plugin-dual-mode/node_modules/lib/index.js

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

tests/webpack-test/configCases/sharing/share-plugin-dual-mode/node_modules/lib/package.json

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

tests/webpack-test/configCases/sharing/share-plugin-dual-mode/node_modules/transitive_lib/index.js

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

tests/webpack-test/configCases/sharing/share-plugin-dual-mode/node_modules/transitive_lib/package.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"lib": "^1.0.0"
4+
}
5+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const { SharePlugin } = require("@rspack/core").sharing;
2+
3+
/** @type {import("../../../../").Configuration} */
4+
module.exports = {
5+
context: `${__dirname}/cjs`,
6+
plugins: [
7+
new SharePlugin({
8+
shared: {
9+
lib: {},
10+
transitive_lib: {},
11+
},
12+
}),
13+
],
14+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
it('should provide library from own package.json', async () => {
2+
expect(await import('lib1')).toEqual(
3+
expect.objectContaining({
4+
default: '[email protected]',
5+
}),
6+
);
7+
});
8+
9+
it('should provide library from parent package.json', async () => {
10+
expect(await import('lib2')).toEqual(
11+
expect.objectContaining({
12+
default: '[email protected]',
13+
}),
14+
);
15+
});

0 commit comments

Comments
 (0)