aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Dylan Conway <dylan.conway567@gmail.com> 2023-07-31 17:31:16 -0700
committerGravatar Dylan Conway <dylan.conway567@gmail.com> 2023-07-31 17:31:16 -0700
commit47a0479bbf10a316c6e41c69f4ae14b978afa989 (patch)
treebf0b5253a0e97f1a9fe3a39f1c72fdf72f90994e
parent8589ba2f1712d68199fbef14f5a4ba9005df3065 (diff)
downloadbun-dylan/fix-module-field-in-exports.tar.gz
bun-dylan/fix-module-field-in-exports.tar.zst
bun-dylan/fix-module-field-in-exports.zip
prefer `module` in `exports`dylan/fix-module-field-in-exports
-rw-r--r--src/resolver/package_json.zig21
-rw-r--r--src/resolver/resolver.zig3
-rw-r--r--test/bundler/esbuild/default.test.ts73
3 files changed, 97 insertions, 0 deletions
diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig
index 75e6a7c98..902829d3a 100644
--- a/src/resolver/package_json.zig
+++ b/src/resolver/package_json.zig
@@ -1248,6 +1248,7 @@ pub const ESModule = struct {
conditions: ConditionsMap,
allocator: std.mem.Allocator,
module_type: *options.ModuleType = undefined,
+ prefer_module_field_in_exports: bool,
pub const Resolution = struct {
status: Status = Status.Undefined,
@@ -1767,6 +1768,8 @@ pub const ESModule = struct {
var did_find_map_entry = false;
var last_map_entry_i: usize = 0;
+ var module_resolution: ?Resolution = null;
+
const slice = object.list.slice();
const keys = slice.items(.key);
for (keys, 0..) |key, i| {
@@ -1792,6 +1795,19 @@ pub const ESModule = struct {
r.module_type.* = .cjs;
}
+ if (strings.eqlComptime(key, "module")) {
+ if (r.prefer_module_field_in_exports) {
+ r.module_type.* = .esm;
+ return result;
+ }
+
+ // Node will not choose the "module" field in "exports". If it's not preferred, bun will
+ // use the "module" field if no other conditions match. This behavior is similar to
+ // the top-level "module" field.
+ module_resolution = result;
+ continue;
+ }
+
return result;
}
@@ -1800,6 +1816,11 @@ pub const ESModule = struct {
}
}
+ if (module_resolution) |result| {
+ r.module_type.* = .esm;
+ return result;
+ }
+
if (r.debug_logs) |log| {
log.addNoteFmt("No keys matched", .{});
}
diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig
index 49ce9ec11..b7044a625 100644
--- a/src/resolver/resolver.zig
+++ b/src/resolver/resolver.zig
@@ -1610,6 +1610,7 @@ pub const Resolver = struct {
.allocator = r.allocator,
.debug_logs = if (r.debug_logs) |*debug| debug else null,
.module_type = &module_type,
+ .prefer_module_field_in_exports = r.prefer_module_field,
};
// Resolve against the path "/", then join it with the absolute
@@ -1875,6 +1876,7 @@ pub const Resolver = struct {
debug
else
null,
+ .prefer_module_field_in_exports = r.prefer_module_field,
};
// Resolve against the path "/", then join it with the absolute
@@ -2853,6 +2855,7 @@ pub const Resolver = struct {
.allocator = r.allocator,
.debug_logs = if (r.debug_logs) |*debug| debug else null,
.module_type = &module_type,
+ .prefer_module_field_in_exports = r.prefer_module_field,
};
const esm_resolution = esmodule.resolveImports(import_path, imports_map.root);
diff --git a/test/bundler/esbuild/default.test.ts b/test/bundler/esbuild/default.test.ts
index ac820848a..0d17312ed 100644
--- a/test/bundler/esbuild/default.test.ts
+++ b/test/bundler/esbuild/default.test.ts
@@ -6836,4 +6836,77 @@ describe("bundler", () => {
stdout: "5 9 2 7",
},
});
+ const fooNodeModule = {
+ "/node_modules/foo/package.json": `
+ {
+ "name": "foo",
+ "version": "2.0.0",
+ "exports": {
+ ".": {
+ "module": "./import.js",
+ "require": "./require.js",
+ "import": "./import.js"
+ }
+ }
+ }
+ `,
+ "/node_modules/foo/import.js": `
+ export const foo = 'import';
+ `,
+ "/node_modules/foo/require.js": `
+ export const foo = 'require';
+ `,
+ };
+ itBundled("default/ExportFieldWithModuleRuntimeImport", {
+ files: {
+ "/entry.js": `
+ import { foo } from 'foo';
+ console.log(foo);
+ `,
+ ...fooNodeModule,
+ },
+ bundling: false,
+ run: {
+ stdout: "import",
+ },
+ });
+ itBundled("default/ExportsFieldWithModuleBundleImport", {
+ files: {
+ "/entry.js": `
+ import { foo } from 'foo';
+ console.log(foo);
+ `,
+ ...fooNodeModule,
+ },
+ bundling: true,
+ run: {
+ stdout: "import",
+ },
+ });
+ itBundled("default/ExportsFieldWithModuleRuntimeRequire", {
+ files: {
+ "/entry.js": `
+ const { foo } = require('foo');
+ console.log(foo);
+ `,
+ ...fooNodeModule,
+ },
+ bundling: false,
+ run: {
+ stdout: "require",
+ },
+ });
+ itBundled("default/ExportsFieldWithModuleBundleRequire", {
+ files: {
+ "/entry.js": `
+ const { foo } = require('foo');
+ console.log(foo);
+ `,
+ ...fooNodeModule,
+ },
+ bundling: true,
+ run: {
+ stdout: "import",
+ },
+ });
});