Skip to content
Open
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
5 changes: 3 additions & 2 deletions src/js_parser/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
if p.should_unwrap_common_js_to_esm() {
if !p.is_control_flow_dead && id.ref_.eql(p.exports_ref) {
if !p.commonjs_named_exports_deoptimized {
if identifier_opts.is_delete_target() {
// `exports.__proto__` is the prototype of `module.exports`, not an export.
if identifier_opts.is_delete_target() || name == b"__proto__" {
p.deoptimize_common_js_named_exports();
return None;
}
Expand Down Expand Up @@ -673,7 +674,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
if p.should_unwrap_common_js_to_esm() {
if !p.is_control_flow_dead {
if !p.commonjs_named_exports_deoptimized {
if identifier_opts.is_delete_target() {
if identifier_opts.is_delete_target() || name == b"__proto__" {
p.deoptimize_common_js_named_exports();
return None;
}
Expand Down
37 changes: 37 additions & 0 deletions test/bundler/bundler_cjs2esm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2280,6 +2280,43 @@ describe("bundler", () => {
stdout: "1 2 false",
},
});
// `exports.__proto__` is the prototype of `module.exports`, not an export
// named "__proto__". A lifted binding plus a namespace getter cannot stand in
// for it, so these files keep their `__commonJS` wrapper.
itBundled("cjs2esm/ExportsProtoMemberKeepsWrapper", {
files: {
"/entry.js": /* js */ `
import dot, * as dotNs from "./dot.cjs";
import bracket from "./bracket.cjs";
import viaModule from "./module.cjs";
import read, { c } from "./read.cjs";
const describe = m => [Object.keys(m), Object.hasOwn(m, "__proto__"), m.inherited, Object.getPrototypeOf(m).inherited];
console.log(JSON.stringify([describe(dot), describe(bracket), describe(viaModule), dotNs.a, dotNs.default === dot, read.isObjectPrototype, c]));
`,
"/dot.cjs": /* js */ `
exports.__proto__ = { inherited: 1 };
exports.a = 1;
`,
"/bracket.cjs": /* js */ `
exports.b = 2;
exports["__proto__"] = { inherited: 2 };
`,
"/module.cjs": /* js */ `
module.exports.c = 3;
module.exports.__proto__ = { inherited: 3 };
`,
"/read.cjs": /* js */ `
exports.c = 4;
exports.isObjectPrototype = exports.__proto__ === Object.prototype;
`,
},
cjs2esm: {
unhandled: ["/dot.cjs", "/bracket.cjs", "/module.cjs", "/read.cjs"],
},
run: {
stdout: JSON.stringify([[["a"], false, 1, 1], [["b"], false, 2, 2], [["c"], false, 3, 3], 1, true, true, 4]),
},
});
// Module code makes a top-level function declaration lexical, so a `var`
// with the same name is a SyntaxError there. A function body allows it, so
// these files keep their `__commonJS` wrapper. In sloppy mode the bundler
Expand Down
Loading