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:

---

7c065e0b6f/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.
This commit is contained in:
Boshen 2023-12-06 12:25:44 +08:00 committed by GitHub
parent 286644714f
commit 2e42e10a1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 9 deletions

View file

@ -18,6 +18,7 @@ fn main() {
println!("request: {request}"); println!("request: {request}");
let options = ResolveOptions { let options = ResolveOptions {
alias_fields: vec![vec!["browser".into()]],
alias: vec![("/asdf".into(), vec![AliasValue::Path("./test.js".into())])], alias: vec![("/asdf".into(), vec![AliasValue::Path("./test.js".into())])],
..ResolveOptions::default() ..ResolveOptions::default()
}; };

View file

@ -277,15 +277,20 @@ impl CachedPathImpl {
let Ok(package_json_string) = fs.read_to_string(&package_json_path) else { let Ok(package_json_string) = fs.read_to_string(&package_json_path) else {
return Ok(None); return Ok(None);
}; };
let package_json_path = if options.symlinks { let real_path = if options.symlinks {
self.realpath(fs)?.join("package.json") self.realpath(fs)?.join("package.json")
} else { } else {
package_json_path package_json_path.clone()
}; };
PackageJson::parse(package_json_path.clone(), &package_json_string, options) PackageJson::parse(
.map(Arc::new) package_json_path.clone(),
.map(Some) real_path,
.map_err(|error| ResolveError::from_serde_json_error(package_json_path, &error)) &package_json_string,
options,
)
.map(Arc::new)
.map(Some)
.map_err(|error| ResolveError::from_serde_json_error(package_json_path, &error))
}) })
.cloned() .cloned()
} }

View file

@ -21,6 +21,10 @@ pub struct PackageJson {
#[serde(skip)] #[serde(skip)]
pub path: PathBuf, pub path: PathBuf,
/// Realpath to `package.json`. Contains the `package.json` filename.
#[serde(skip)]
pub realpath: PathBuf,
#[serde(skip)] #[serde(skip)]
#[serde(default)] #[serde(default)]
pub raw_json: Arc<serde_json::Value>, pub raw_json: Arc<serde_json::Value>,
@ -117,6 +121,7 @@ impl PackageJson {
/// # Errors /// # Errors
pub fn parse( pub fn parse(
path: PathBuf, path: PathBuf,
realpath: PathBuf,
json: &str, json: &str,
options: &ResolveOptions, options: &ResolveOptions,
) -> Result<Self, serde_json::Error> { ) -> Result<Self, serde_json::Error> {
@ -171,6 +176,7 @@ impl PackageJson {
} }
package_json.path = path; package_json.path = path;
package_json.realpath = realpath;
package_json.raw_json = Arc::new(package_json_value); package_json.raw_json = Arc::new(package_json_value);
Ok(package_json) Ok(package_json)
} }
@ -193,7 +199,7 @@ impl PackageJson {
Some(value) Some(value)
} }
/// Directory to `package.json` /// Raw json of `package.json`
pub fn raw_json(&self) -> &serde_json::Value { pub fn raw_json(&self) -> &serde_json::Value {
self.raw_json.as_ref() self.raw_json.as_ref()
} }
@ -204,8 +210,8 @@ impl PackageJson {
/// ///
/// * When the package.json path is misconfigured. /// * When the package.json path is misconfigured.
pub fn directory(&self) -> &Path { pub fn directory(&self) -> &Path {
debug_assert!(self.path.file_name().is_some_and(|x| x == "package.json")); debug_assert!(self.realpath.file_name().is_some_and(|x| x == "package.json"));
self.path.parent().unwrap() self.realpath.parent().unwrap()
} }
/// Resolve the request string for this package.json by looking at the `browser` field. /// Resolve the request string for this package.json by looking at the `browser` field.