Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/resolver/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5001,7 +5001,7 @@ impl<'a> Resolver<'a> {
extension_order: options::ExtOrder,
out: &mut MatchResult,
) -> MatchStatus {
let mut field_rel_path = _field_rel_path;
let field_rel_path = _field_rel_path;
// Is this a directory?
if let Some(debug) = self.debug_logs.as_mut() {
debug.add_note_fmt(format_args!(
Expand All @@ -5022,14 +5022,18 @@ impl<'a> Resolver<'a> {
}};
}

let mut field_abs_path: &[u8] = self
.fs_ref()
.abs_buf(&[path, field_rel_path], bufs!(field_abs_path));

if self.care_about_browser_field {
// Potentially remap using the "browser" field
if let Some(browser_scope) = dir_info.get_enclosing_browser_scope() {
if let Some(browser_json) = browser_scope.package_json() {
if let Some(remap) = self
.check_browser_map::<{ BrowserMapPathKind::AbsolutePath }>(
&browser_scope,
field_rel_path,
field_abs_path,
)
{
// Is the path disabled?
Expand All @@ -5049,13 +5053,14 @@ impl<'a> Resolver<'a> {
dec_ret!(MatchStatus::Success);
}

field_rel_path = remap;
// `remap` is relative to the package that owns the browser map.
field_abs_path = self
.fs_ref()
.abs_buf(&[browser_scope.abs_path, remap], bufs!(field_abs_path));
}
}
}
}
let _paths = [path, field_rel_path];
let field_abs_path = self.fs_ref().abs_buf(&_paths, bufs!(field_abs_path));

// Is this a file?
if let Some(result) = self.load_as_file(field_abs_path, extension_order) {
Expand Down Expand Up @@ -5258,16 +5263,18 @@ impl<'a> Resolver<'a> {
const FIELD_REL_PATH: &[u8] = b"index";

if let Some(browser_json) = browser_scope.package_json() {
let index_paths = [path, FIELD_REL_PATH];
let index_abs_path = self.fs_ref().abs_buf(&index_paths, bufs!(remap_path));
if let Some(remap) = self
.check_browser_map::<{ BrowserMapPathKind::AbsolutePath }>(
&browser_scope,
FIELD_REL_PATH,
index_abs_path,
)
Comment thread
robobun marked this conversation as resolved.
{
// Is the path disabled?
if remap.is_empty() {
let paths = [path, FIELD_REL_PATH];
let new_path = self.fs_ref().abs_buf(&paths, bufs!(remap_path));
let new_path =
self.fs_ref().abs_alloc(&index_paths).expect("unreachable");
let mut _path = Path::init(new_path);
_path.is_disabled = true;
Comment thread
robobun marked this conversation as resolved.
*out = MatchResult {
Expand All @@ -5281,7 +5288,8 @@ impl<'a> Resolver<'a> {
return MatchStatus::Success;
}

let new_paths = [path, remap];
// `remap` is relative to the browser scope, which may be an ancestor of `path`.
let new_paths = [browser_scope.abs_path, remap];
let remapped_abs = self.fs_ref().abs_buf(&new_paths, bufs!(remap_path));

// Is this a file
Expand Down
145 changes: 145 additions & 0 deletions test/bundler/esbuild/packagejson.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2105,4 +2105,149 @@ describe("bundler", () => {
stdout: "browser-override",
},
});
// The "main" field value is checked against the browser map before extension
// resolution. Packages like jszip ship
// "main": "./lib/index",
// "browser": {"./lib/index": "./dist/jszip.min.js"}
// and expect the prebuilt bundle to be picked for browser targets.
itBundled("packagejson/BrowserMapMainFieldNoExt", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
import value from 'demo-pkg'
console.log(value)
`,
"/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
{
"main": "./lib/index",
"browser": {
"./lib/index": "./dist/demo-pkg.min.js"
}
}
`,
"/Users/user/project/node_modules/demo-pkg/lib/index.js": `module.exports = 'lib'`,
"/Users/user/project/node_modules/demo-pkg/dist/demo-pkg.min.js": `module.exports = 'prebuilt'`,
},
target: "browser",
run: {
stdout: "prebuilt",
},
});
// Extension matching for main-field browser remaps should match esbuild:
// the main-field value is probed as-is and with extensions appended, so an
// extensionless main still hits a ".js"-keyed browser entry, but a ".js"
// main does not hit an extensionless browser key.
itBundled("packagejson/BrowserMapMainFieldExtPermutations", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
import a from 'pkg-a'
import b from 'pkg-b'
import c from 'pkg-c'
import d from 'pkg-d'
console.log(a, b, c, d)
`,
"/Users/user/project/node_modules/pkg-a/package.json": `{"main":"./lib/index.js","browser":{"./lib/index.js":"./browser.js"}}`,
"/Users/user/project/node_modules/pkg-a/lib/index.js": `module.exports = 'lib'`,
"/Users/user/project/node_modules/pkg-a/browser.js": `module.exports = 'browser'`,
"/Users/user/project/node_modules/pkg-b/package.json": `{"main":"./lib/index","browser":{"./lib/index.js":"./browser.js"}}`,
"/Users/user/project/node_modules/pkg-b/lib/index.js": `module.exports = 'lib'`,
"/Users/user/project/node_modules/pkg-b/browser.js": `module.exports = 'browser'`,
"/Users/user/project/node_modules/pkg-c/package.json": `{"main":"./lib/index.js","browser":{"./lib/index":"./browser.js"}}`,
"/Users/user/project/node_modules/pkg-c/lib/index.js": `module.exports = 'lib'`,
"/Users/user/project/node_modules/pkg-c/browser.js": `module.exports = 'browser'`,
"/Users/user/project/node_modules/pkg-d/package.json": `{"main":"./lib/index","browser":{"./lib/index":"./browser.js"}}`,
"/Users/user/project/node_modules/pkg-d/lib/index.js": `module.exports = 'lib'`,
"/Users/user/project/node_modules/pkg-d/browser.js": `module.exports = 'browser'`,
},
target: "browser",
run: {
stdout: "browser browser lib browser",
},
});
itBundled("packagejson/BrowserMapMainFieldDisabledNoExt", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
console.log(require('demo-pkg') === 'lib' ? 'loaded-lib' : 'disabled')
`,
"/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
{
"main": "./lib/index",
"browser": {
"./lib/index": false
}
}
`,
"/Users/user/project/node_modules/demo-pkg/lib/index.js": `module.exports = 'lib'`,
},
target: "browser",
run: {
stdout: "disabled",
},
});
// A subpath that resolves to a directory's implicit "index" is checked
// against the enclosing package's browser map, and the remap target is
// resolved relative to that package (not the subdirectory).
itBundled("packagejson/BrowserMapSubpathDirIndex", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
import value from 'demo-pkg/sub'
console.log(value)
`,
"/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
{
"browser": {
"./sub/index.js": "./browser-sub.js"
}
}
`,
"/Users/user/project/node_modules/demo-pkg/sub/index.js": `module.exports = 'sub-index'`,
"/Users/user/project/node_modules/demo-pkg/browser-sub.js": `module.exports = 'browser-sub'`,
},
target: "browser",
run: {
stdout: "browser-sub",
},
});
itBundled("packagejson/BrowserMapSubpathDirIndexDisabled", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
console.log(require('demo-pkg/sub') === 'sub-index' ? 'loaded' : 'disabled')
`,
"/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
{
"browser": {
"./sub/index": false
}
}
`,
"/Users/user/project/node_modules/demo-pkg/sub/index.js": `module.exports = 'sub-index'`,
},
target: "browser",
run: {
stdout: "disabled",
},
});
// When "main" points at a directory, the implicit "<dir>/index" is checked
// against the browser map before extension resolution.
itBundled("packagejson/BrowserMapMainFieldDirIndexNoExt", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
import value from 'demo-pkg'
console.log(value)
`,
"/Users/user/project/node_modules/demo-pkg/package.json": /* json */ `
{
"main": "./lib",
"browser": {
"./lib/index": "./browser.js"
}
}
`,
"/Users/user/project/node_modules/demo-pkg/lib/index.js": `module.exports = 'lib'`,
"/Users/user/project/node_modules/demo-pkg/browser.js": `module.exports = 'browser'`,
},
target: "browser",
run: {
stdout: "browser",
},
});
});
Loading