From 2e42e10a1baebdb49cff5e0f72cf07191d85d159 Mon Sep 17 00:00:00 2001 From: Boshen Date: Wed, 6 Dec 2023 12:25:44 +0800 Subject: [PATCH] feat(resolver): add a `realpath` to package.json (#1634) Using the `realpath` for resolving browser field will lead to missing queries. This fixes a cases where `browserField` fails to read. --- `styled-components` is using a trick for loading browser modules: --- https://github.com/styled-components/styled-components/blob/7c065e0b6f890760d7a6759ec5e4a95775b6e688/packages/styled-components/package.json#L6C1-L12C5 ```json "main": "dist/styled-components.cjs.js", "module": "./dist/styled-components.esm.js", "browser": { "./dist/styled-components.esm.js": "./dist/styled-components.browser.esm.js", "./dist/styled-components.cjs.js": "./dist/styled-components.browser.cjs.js" }, ``` Module resolution has to go from `"module": "./dist/styled-components.esm.js"`, then to `browser`'s `"./dist/styled-components.esm.js": "./dist/styled-components.browser.esm.js"` part in order for things to get resolved correctly. --- Fixtures are hard to setup for this test case due to needing symlinks, I've created https://github.com/oxc-project/oxc_resolver for tacking such cases. --- crates/oxc_resolver/examples/resolver.rs | 1 + crates/oxc_resolver/src/cache.rs | 17 +++++++++++------ crates/oxc_resolver/src/package_json.rs | 12 +++++++++--- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/crates/oxc_resolver/examples/resolver.rs b/crates/oxc_resolver/examples/resolver.rs index 8de8cc7e7..b1307ca45 100644 --- a/crates/oxc_resolver/examples/resolver.rs +++ b/crates/oxc_resolver/examples/resolver.rs @@ -18,6 +18,7 @@ fn main() { println!("request: {request}"); let options = ResolveOptions { + alias_fields: vec![vec!["browser".into()]], alias: vec![("/asdf".into(), vec![AliasValue::Path("./test.js".into())])], ..ResolveOptions::default() }; diff --git a/crates/oxc_resolver/src/cache.rs b/crates/oxc_resolver/src/cache.rs index 086794507..031d8eaa5 100644 --- a/crates/oxc_resolver/src/cache.rs +++ b/crates/oxc_resolver/src/cache.rs @@ -277,15 +277,20 @@ impl CachedPathImpl { let Ok(package_json_string) = fs.read_to_string(&package_json_path) else { return Ok(None); }; - let package_json_path = if options.symlinks { + let real_path = if options.symlinks { self.realpath(fs)?.join("package.json") } else { - package_json_path + package_json_path.clone() }; - PackageJson::parse(package_json_path.clone(), &package_json_string, options) - .map(Arc::new) - .map(Some) - .map_err(|error| ResolveError::from_serde_json_error(package_json_path, &error)) + PackageJson::parse( + package_json_path.clone(), + real_path, + &package_json_string, + options, + ) + .map(Arc::new) + .map(Some) + .map_err(|error| ResolveError::from_serde_json_error(package_json_path, &error)) }) .cloned() } diff --git a/crates/oxc_resolver/src/package_json.rs b/crates/oxc_resolver/src/package_json.rs index e3da5a945..4bb26d9ce 100644 --- a/crates/oxc_resolver/src/package_json.rs +++ b/crates/oxc_resolver/src/package_json.rs @@ -21,6 +21,10 @@ pub struct PackageJson { #[serde(skip)] pub path: PathBuf, + /// Realpath to `package.json`. Contains the `package.json` filename. + #[serde(skip)] + pub realpath: PathBuf, + #[serde(skip)] #[serde(default)] pub raw_json: Arc, @@ -117,6 +121,7 @@ impl PackageJson { /// # Errors pub fn parse( path: PathBuf, + realpath: PathBuf, json: &str, options: &ResolveOptions, ) -> Result { @@ -171,6 +176,7 @@ impl PackageJson { } package_json.path = path; + package_json.realpath = realpath; package_json.raw_json = Arc::new(package_json_value); Ok(package_json) } @@ -193,7 +199,7 @@ impl PackageJson { Some(value) } - /// Directory to `package.json` + /// Raw json of `package.json` pub fn raw_json(&self) -> &serde_json::Value { self.raw_json.as_ref() } @@ -204,8 +210,8 @@ impl PackageJson { /// /// * When the package.json path is misconfigured. pub fn directory(&self) -> &Path { - debug_assert!(self.path.file_name().is_some_and(|x| x == "package.json")); - self.path.parent().unwrap() + debug_assert!(self.realpath.file_name().is_some_and(|x| x == "package.json")); + self.realpath.parent().unwrap() } /// Resolve the request string for this package.json by looking at the `browser` field.