From 3a9d5e7c31d118781d8164a1b67c37a6bc26877b Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 18 Nov 2025 07:51:38 +0000 Subject: [PATCH] fix: do not resolve to `node_modules/pacakge/index` (#849) fixes #845 The option `main_files` is kind of confusing, it's supposed to be the file stem without the extension (e.g. index), but somehow it ended up being a lookup for `index` then `index.js` instead of just `index.js`. This reduces an extra "is file" system call for `node_modules/package/index`. --- src/lib.rs | 4 +- src/tests/alias.rs | 104 +++++++++++++++++------------------ src/tests/extension_alias.rs | 2 +- src/tests/fallback.rs | 72 ++++++++++++------------ src/tests/imports_field.rs | 2 +- src/tests/missing.rs | 1 - 6 files changed, 92 insertions(+), 93 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5dcbae85..41c3e59b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -756,7 +756,7 @@ impl ResolverGeneric { for main_file in &self.options.main_files { let cached_path = cached_path.normalize_with(main_file, self.cache.as_ref()); if self.options.enforce_extension.is_disabled() - && let Some(path) = self.load_alias_or_file(&cached_path, ctx)? + && let Some(path) = self.load_browser_field_or_alias(&cached_path, ctx)? && self.check_restrictions(path.path()) { return Ok(Some(path)); @@ -1515,7 +1515,7 @@ impl ResolverGeneric { .clone_with_options(ResolveOptions { tsconfig: None, extensions: vec![".json".into()], - main_files: vec!["tsconfig.json".into()], + main_files: vec!["tsconfig".into()], #[cfg(feature = "yarn_pnp")] yarn_pnp: self.options.yarn_pnp, #[cfg(feature = "yarn_pnp")] diff --git a/src/tests/alias.rs b/src/tests/alias.rs index 6d0c37a1..c7fda5b6 100644 --- a/src/tests/alias.rs +++ b/src/tests/alias.rs @@ -18,18 +18,18 @@ fn alias() { let f = Path::new("/"); let file_system = MemoryFS::new(&[ - ("/a/index", ""), - ("/a/dir/index", ""), - ("/recursive/index", ""), - ("/recursive/dir/index", ""), - ("/b/index", ""), - ("/b/dir/index", ""), - ("/c/index", ""), - ("/c/dir/index", ""), - ("/d/index.js", ""), + ("/a/index.js", ""), + ("/a/dir/index.js", ""), + ("/recursive/index.js", ""), + ("/recursive/dir/index.js", ""), + ("/b/index.js", ""), + ("/b/dir/index.js", ""), + ("/c/index.js", ""), + ("/c/dir/index.js", ""), + ("/d/index.js.js", ""), ("/d/dir/.empty", ""), - ("/e/index", ""), - ("/e/anotherDir/index", ""), + ("/e/index.js", ""), + ("/e/anotherDir/index.js", ""), ("/e/dir/file", ""), ("/dashed-name", ""), ]); @@ -39,8 +39,8 @@ fn alias() { ResolveOptions { alias: vec![ ("aliasA".into(), vec![AliasValue::from("a")]), - ("b$".into(), vec![AliasValue::from("a/index")]), - ("c$".into(), vec![AliasValue::from("/a/index")]), + ("b$".into(), vec![AliasValue::from("a/index.js")]), + ("c$".into(), vec![AliasValue::from("/a/index.js")]), ( "multiAlias".into(), vec![ @@ -53,7 +53,7 @@ fn alias() { ), ("recursive".into(), vec![AliasValue::from("recursive/dir")]), ("/d/dir".into(), vec![AliasValue::from("/c/dir")]), - ("/d/index.js".into(), vec![AliasValue::from("/c/index")]), + ("/d/index.js".into(), vec![AliasValue::from("/c/index.js")]), ("#".into(), vec![AliasValue::from("/c/dir")]), ("@".into(), vec![AliasValue::from("/c/dir")]), ("ignored".into(), vec![AliasValue::Ignore]), @@ -75,51 +75,51 @@ fn alias() { #[rustfmt::skip] let pass = [ - ("should resolve a not aliased module 1", "a", "/a/index"), - ("should resolve a not aliased module 2", "a/index", "/a/index"), - ("should resolve a not aliased module 3", "a/dir", "/a/dir/index"), - ("should resolve a not aliased module 4", "a/dir/index", "/a/dir/index"), - ("should resolve an aliased module 1", "aliasA", "/a/index"), - ("should resolve an aliased module 2", "aliasA/index", "/a/index"), - ("should resolve an aliased module 3", "aliasA/dir", "/a/dir/index"), - ("should resolve an aliased module 4", "aliasA/dir/index", "/a/dir/index"), - ("should resolve '#' alias 1", "#", "/c/dir/index"), - ("should resolve '#' alias 2", "#/index", "/c/dir/index"), - ("should resolve '@' alias 1", "@", "/c/dir/index"), - ("should resolve '@' alias 2", "@/index", "/c/dir/index"), - ("should resolve '@' alias 3", "@/", "/c/dir/index"), - ("should resolve a recursive aliased module 1", "recursive", "/recursive/dir/index"), - ("should resolve a recursive aliased module 2", "recursive/index", "/recursive/dir/index"), - ("should resolve a recursive aliased module 3", "recursive/dir", "/recursive/dir/index"), - ("should resolve a recursive aliased module 4", "recursive/dir/index", "/recursive/dir/index"), - ("should resolve a file aliased module 1", "b", "/a/index"), - ("should resolve a file aliased module 2", "c", "/a/index"), - ("should resolve a file aliased module with a query 1", "b?query", "/a/index?query"), - ("should resolve a file aliased module with a query 2", "c?query", "/a/index?query"), - ("should resolve a path in a file aliased module 1", "b/index", "/b/index"), - ("should resolve a path in a file aliased module 2", "b/dir", "/b/dir/index"), - ("should resolve a path in a file aliased module 3", "b/dir/index", "/b/dir/index"), - ("should resolve a path in a file aliased module 4", "c/index", "/c/index"), - ("should resolve a path in a file aliased module 5", "c/dir", "/c/dir/index"), - ("should resolve a path in a file aliased module 6", "c/dir/index", "/c/dir/index"), - ("should resolve a file aliased file 1", "d", "/c/index"), - ("should resolve a file aliased file 2", "d/dir/index", "/c/dir/index"), + ("should resolve a not aliased module 1", "a", "/a/index.js"), + ("should resolve a not aliased module 2", "a/index.js", "/a/index.js"), + ("should resolve a not aliased module 3", "a/dir", "/a/dir/index.js"), + ("should resolve a not aliased module 4", "a/dir/index.js", "/a/dir/index.js"), + ("should resolve an aliased module 1", "aliasA", "/a/index.js"), + ("should resolve an aliased module 2", "aliasA/index.js", "/a/index.js"), + ("should resolve an aliased module 3", "aliasA/dir", "/a/dir/index.js"), + ("should resolve an aliased module 4", "aliasA/dir/index.js", "/a/dir/index.js"), + ("should resolve '#' alias 1", "#", "/c/dir/index.js"), + ("should resolve '#' alias 2", "#/index.js", "/c/dir/index.js"), + ("should resolve '@' alias 1", "@", "/c/dir/index.js"), + ("should resolve '@' alias 2", "@/index.js", "/c/dir/index.js"), + ("should resolve '@' alias 3", "@/", "/c/dir/index.js"), + ("should resolve a recursive aliased module 1", "recursive", "/recursive/dir/index.js"), + ("should resolve a recursive aliased module 2", "recursive/index.js", "/recursive/dir/index.js"), + ("should resolve a recursive aliased module 3", "recursive/dir", "/recursive/dir/index.js"), + ("should resolve a recursive aliased module 4", "recursive/dir/index.js", "/recursive/dir/index.js"), + ("should resolve a file aliased module 1", "b", "/a/index.js"), + ("should resolve a file aliased module 2", "c", "/a/index.js"), + ("should resolve a file aliased module with a query 1", "b?query", "/a/index.js?query"), + ("should resolve a file aliased module with a query 2", "c?query", "/a/index.js?query"), + ("should resolve a path in a file aliased module 1", "b/index.js", "/b/index.js"), + ("should resolve a path in a file aliased module 2", "b/dir", "/b/dir/index.js"), + ("should resolve a path in a file aliased module 3", "b/dir/index.js", "/b/dir/index.js"), + ("should resolve a path in a file aliased module 4", "c/index.js", "/c/index.js"), + ("should resolve a path in a file aliased module 5", "c/dir", "/c/dir/index.js"), + ("should resolve a path in a file aliased module 6", "c/dir/index.js", "/c/dir/index.js"), + ("should resolve a file aliased file 1", "d", "/c/index.js"), + ("should resolve a file aliased file 2", "d/dir/index.js", "/c/dir/index.js"), ("should resolve a file in multiple aliased dirs 1", "multiAlias/dir/file", "/e/dir/file"), - ("should resolve a file in multiple aliased dirs 2", "multiAlias/anotherDir", "/e/anotherDir/index"), + ("should resolve a file in multiple aliased dirs 2", "multiAlias/anotherDir", "/e/anotherDir/index.js"), // wildcard - ("should resolve wildcard alias 1", "@a", "/a/index"), - ("should resolve wildcard alias 2", "@a/dir", "/a/dir/index"), + ("should resolve wildcard alias 1", "@a", "/a/index.js"), + ("should resolve wildcard alias 2", "@a/dir", "/a/dir/index.js"), ("should resolve wildcard alias 3", "@e/dir/file", "/e/dir/file"), - ("should resolve wildcard alias 4", "@e/anotherDir", "/e/anotherDir/index"), + ("should resolve wildcard alias 4", "@e/anotherDir", "/e/anotherDir/index.js"), ("should resolve wildcard alias 5", "@e/dir/file", "/e/dir/file"), // added to test value without wildcard - ("should resolve scoped package name with sub dir 1", "@adir/index", "/a/index"), - ("should resolve scoped package name with sub dir 2", "@adir/dir", "/a/index"), + ("should resolve scoped package name with sub dir 1", "@adir/index.js", "/a/index.js"), + ("should resolve scoped package name with sub dir 2", "@adir/dir", "/a/index.js"), // not part of enhanced-resolve, added to make sure query in alias value works - ("should resolve query in alias value", "alias_query?query_before", "/a/index?query_after"), - ("should resolve query in alias value", "alias_fragment#fragment_before", "/a/index#fragment_after"), + ("should resolve query in alias value", "alias_query?query_before", "/a/index.js?query_after"), + ("should resolve query in alias value", "alias_fragment#fragment_before", "/a/index.js#fragment_after"), ("should resolve dashed name", "dashed-name", "/dashed-name"), - ("should resolve scoped package name with sub dir", "@scope/package-name/file", "/c/dir/index"), + ("should resolve scoped package name with sub dir", "@scope/package-name/file", "/c/dir/index.js"), ]; for (comment, request, expected) in pass { diff --git a/src/tests/extension_alias.rs b/src/tests/extension_alias.rs index 43f2f075..4978bc1c 100644 --- a/src/tests/extension_alias.rs +++ b/src/tests/extension_alias.rs @@ -57,7 +57,7 @@ fn not_apply_to_extension_nor_main_files() { let resolver = Resolver::new(ResolveOptions { extensions: vec![".js".into()], - main_files: vec!["index.js".into()], + main_files: vec!["index".into()], extension_alias: vec![(".js".into(), vec![])], ..ResolveOptions::default() }); diff --git a/src/tests/fallback.rs b/src/tests/fallback.rs index c5bd4e76..8dccc3c8 100644 --- a/src/tests/fallback.rs +++ b/src/tests/fallback.rs @@ -11,20 +11,20 @@ fn fallback() { let f = Path::new("/"); let file_system = MemoryFS::new(&[ - ("/a/index", ""), - ("/a/dir/index", ""), - ("/recursive/index", ""), - ("/recursive/dir/index", ""), + ("/a/index.js", ""), + ("/a/dir/index.js", ""), + ("/recursive/index.js", ""), + ("/recursive/dir/index.js", ""), ("/recursive/dir/file", ""), - ("/recursive/dir/dir/index", ""), - ("/b/index", ""), - ("/b/dir/index", ""), - ("/c/index", ""), - ("/c/dir/index", ""), - ("/d/index.js", ""), + ("/recursive/dir/dir/index.js", ""), + ("/b/index.js", ""), + ("/b/dir/index.js", ""), + ("/c/index.js", ""), + ("/c/dir/index.js", ""), + ("/d/index.js.js", ""), ("/d/dir/.empty", ""), - ("/e/index", ""), - ("/e/anotherDir/index", ""), + ("/e/index.js", ""), + ("/e/anotherDir/index.js", ""), ("/e/dir/file", ""), ]); @@ -33,8 +33,8 @@ fn fallback() { ResolveOptions { fallback: vec![ ("aliasA".into(), vec![AliasValue::Path("a".into())]), - ("b$".into(), vec![AliasValue::Path("a/index".into())]), - ("c$".into(), vec![AliasValue::Path("/a/index".into())]), + ("b$".into(), vec![AliasValue::Path("a/index.js".into())]), + ("c$".into(), vec![AliasValue::Path("/a/index.js".into())]), ( "multiAlias".into(), vec![ @@ -47,7 +47,7 @@ fn fallback() { ), ("recursive".into(), vec![AliasValue::Path("recursive/dir".into())]), ("/d/dir".into(), vec![AliasValue::Path("/c/dir".into())]), - ("/d/index.js".into(), vec![AliasValue::Path("/c/index".into())]), + ("/d/index.js.js".into(), vec![AliasValue::Path("/c/index.js".into())]), ("ignored".into(), vec![AliasValue::Ignore]), ("node:path".into(), vec![AliasValue::Ignore]), ], @@ -58,29 +58,29 @@ fn fallback() { #[rustfmt::skip] let pass = [ - ("should resolve a not aliased module 1", "a", "/a/index"), - ("should resolve a not aliased module 2", "a/index", "/a/index"), - ("should resolve a not aliased module 3", "a/dir", "/a/dir/index"), - ("should resolve a not aliased module 4", "a/dir/index", "/a/dir/index"), - ("should resolve an fallback module 1", "aliasA", "/a/index"), - ("should resolve an fallback module 2", "aliasA/index", "/a/index"), - ("should resolve an fallback module 3", "aliasA/dir", "/a/dir/index"), - ("should resolve an fallback module 4", "aliasA/dir/index", "/a/dir/index"), - ("should resolve a recursive aliased module 1", "recursive", "/recursive/index"), - ("should resolve a recursive aliased module 2", "recursive/index", "/recursive/index"), - ("should resolve a recursive aliased module 3", "recursive/dir", "/recursive/dir/index"), - ("should resolve a recursive aliased module 4", "recursive/dir/index", "/recursive/dir/index"), + ("should resolve a not aliased module 1", "a", "/a/index.js"), + ("should resolve a not aliased module 2", "a/index.js", "/a/index.js"), + ("should resolve a not aliased module 3", "a/dir", "/a/dir/index.js"), + ("should resolve a not aliased module 4", "a/dir/index.js", "/a/dir/index.js"), + ("should resolve an fallback module 1", "aliasA", "/a/index.js"), + ("should resolve an fallback module 2", "aliasA/index.js", "/a/index.js"), + ("should resolve an fallback module 3", "aliasA/dir", "/a/dir/index.js"), + ("should resolve an fallback module 4", "aliasA/dir/index.js", "/a/dir/index.js"), + ("should resolve a recursive aliased module 1", "recursive", "/recursive/index.js"), + ("should resolve a recursive aliased module 2", "recursive/index.js", "/recursive/index.js"), + ("should resolve a recursive aliased module 3", "recursive/dir", "/recursive/dir/index.js"), + ("should resolve a recursive aliased module 4", "recursive/dir/index.js", "/recursive/dir/index.js"), ("should resolve a recursive aliased module 5", "recursive/file", "/recursive/dir/file"), - ("should resolve a file aliased module with a query 1", "b?query", "/b/index?query"), - ("should resolve a file aliased module with a query 2", "c?query", "/c/index?query"), - ("should resolve a path in a file aliased module 1", "b/index", "/b/index"), - ("should resolve a path in a file aliased module 2", "b/dir", "/b/dir/index"), - ("should resolve a path in a file aliased module 3", "b/dir/index", "/b/dir/index"), - ("should resolve a path in a file aliased module 4", "c/index", "/c/index"), - ("should resolve a path in a file aliased module 5", "c/dir", "/c/dir/index"), - ("should resolve a path in a file aliased module 6", "c/dir/index", "/c/dir/index"), + ("should resolve a file aliased module with a query 1", "b?query", "/b/index.js?query"), + ("should resolve a file aliased module with a query 2", "c?query", "/c/index.js?query"), + ("should resolve a path in a file aliased module 1", "b/index.js", "/b/index.js"), + ("should resolve a path in a file aliased module 2", "b/dir", "/b/dir/index.js"), + ("should resolve a path in a file aliased module 3", "b/dir/index.js", "/b/dir/index.js"), + ("should resolve a path in a file aliased module 4", "c/index.js", "/c/index.js"), + ("should resolve a path in a file aliased module 5", "c/dir", "/c/dir/index.js"), + ("should resolve a path in a file aliased module 6", "c/dir/index.js", "/c/dir/index.js"), ("should resolve a file in multiple aliased dirs 1", "multiAlias/dir/file", "/e/dir/file"), - ("should resolve a file in multiple aliased dirs 2", "multiAlias/anotherDir", "/e/anotherDir/index"), + ("should resolve a file in multiple aliased dirs 2", "multiAlias/anotherDir", "/e/anotherDir/index.js"), ]; for (comment, request, expected) in pass { diff --git a/src/tests/imports_field.rs b/src/tests/imports_field.rs index 7ec62429..95a34344 100644 --- a/src/tests/imports_field.rs +++ b/src/tests/imports_field.rs @@ -15,7 +15,7 @@ fn test_simple() { let resolver = Resolver::new(ResolveOptions { extensions: vec![".js".into()], - main_files: vec!["index.js".into()], + main_files: vec!["index".into()], condition_names: vec!["webpack".into()], ..ResolveOptions::default() }); diff --git a/src/tests/missing.rs b/src/tests/missing.rs index 0a284f5d..28f2d509 100644 --- a/src/tests/missing.rs +++ b/src/tests/missing.rs @@ -37,7 +37,6 @@ fn test() { ( "m1/", vec![ - f.join("node_modules/m1/index"), f.join("node_modules/m1/index.js"), f.join("node_modules/m1/index.json"), f.join("node_modules/m1/index.node"),