diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ede147be9d..c56c67acfb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +* Avoid generating an enumerable `default` import for CommonJS files in Babel mode ([#2097](https://github.com/evanw/esbuild/issues/2097)) + + Importing a CommonJS module into an ES module can be done in two different ways. In node mode the `default` import is always set to `module.exports`, while in Babel mode the `default` import passes through to `module.exports.default` instead. Node mode is triggered when the importing file ends in `.mjs`, has `type: "module"` in its `package.json` file, or the imported module does not have a `__esModule` marker. + + Previously esbuild always created the forwarding `default` import in Babel mode, even if `module.exports` had no property called `default`. This was problematic because the getter named `default` still showed up as a property on the imported namespace object, and could potentially interfere with code that iterated over the properties of the imported namespace object. With this release the getter named `default` will now only be added in Babel mode if the `default` property exists at the time of the import. + ## 0.14.26 * Fix a tree shaking regression regarding `var` declarations ([#2080](https://github.com/evanw/esbuild/issues/2080), [#2085](https://github.com/evanw/esbuild/pull/2085), [#2098](https://github.com/evanw/esbuild/issues/2098), [#2099](https://github.com/evanw/esbuild/issues/2099)) diff --git a/internal/bundler/snapshots/snapshots_splitting.txt b/internal/bundler/snapshots/snapshots_splitting.txt index 97632c329cd..a44d2dab1c3 100644 --- a/internal/bundler/snapshots/snapshots_splitting.txt +++ b/internal/bundler/snapshots/snapshots_splitting.txt @@ -205,19 +205,19 @@ TestSplittingDynamicAndNotDynamicCommonJSIntoES6 import { __toESM, require_foo -} from "./chunk-KUHUE66N.js"; +} from "./chunk-6FVSQLGP.js"; // entry.js var import_foo = __toESM(require_foo()); -import("./foo-U6JCMRHQ.js").then(({ default: { bar: b } }) => console.log(import_foo.bar, b)); +import("./foo-NCFYBVPB.js").then(({ default: { bar: b } }) => console.log(import_foo.bar, b)); ----------- /out/foo-U6JCMRHQ.js ---------- +---------- /out/foo-NCFYBVPB.js ---------- import { require_foo -} from "./chunk-KUHUE66N.js"; +} from "./chunk-6FVSQLGP.js"; export default require_foo(); ----------- /out/chunk-KUHUE66N.js ---------- +---------- /out/chunk-6FVSQLGP.js ---------- // foo.js var require_foo = __commonJS({ "foo.js"(exports) { @@ -260,9 +260,9 @@ export { TestSplittingDynamicCommonJSIntoES6 ---------- /out/entry.js ---------- // entry.js -import("./foo-PPQD77K4.js").then(({ default: { bar } }) => console.log(bar)); +import("./foo-MGFNEEYE.js").then(({ default: { bar } }) => console.log(bar)); ----------- /out/foo-PPQD77K4.js ---------- +---------- /out/foo-MGFNEEYE.js ---------- // foo.js var require_foo = __commonJS({ "foo.js"(exports) { @@ -317,7 +317,7 @@ TestSplittingHybridESMAndCJSIssue617 import { foo, init_a -} from "./chunk-QRBKE4XE.js"; +} from "./chunk-WNGDXRWX.js"; init_a(); export { foo @@ -328,7 +328,7 @@ import { __toCommonJS, a_exports, init_a -} from "./chunk-QRBKE4XE.js"; +} from "./chunk-WNGDXRWX.js"; // b.js var bar = (init_a(), __toCommonJS(a_exports)); @@ -336,7 +336,7 @@ export { bar }; ----------- /out/chunk-QRBKE4XE.js ---------- +---------- /out/chunk-WNGDXRWX.js ---------- // a.js var a_exports = {}; __export(a_exports, { @@ -487,7 +487,7 @@ TestSplittingSharedCommonJSIntoES6 ---------- /out/a.js ---------- import { require_shared -} from "./chunk-KTJ3L72M.js"; +} from "./chunk-GI5SL2RW.js"; // a.js var { foo } = require_shared(); @@ -496,13 +496,13 @@ console.log(foo); ---------- /out/b.js ---------- import { require_shared -} from "./chunk-KTJ3L72M.js"; +} from "./chunk-GI5SL2RW.js"; // b.js var { foo } = require_shared(); console.log(foo); ----------- /out/chunk-KTJ3L72M.js ---------- +---------- /out/chunk-GI5SL2RW.js ---------- // shared.js var require_shared = __commonJS({ "shared.js"(exports) { diff --git a/internal/runtime/runtime.go b/internal/runtime/runtime.go index 64ccbb8ba42..801972e54bb 100644 --- a/internal/runtime/runtime.go +++ b/internal/runtime/runtime.go @@ -112,9 +112,6 @@ func code(isES6 bool) string { } export var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)) - // Tells importing modules that this can be considered an ES module - var __markAsModule = target => __defProp(target, '__esModule', { value: true }) - // Update the "name" property on the function or class for "--keep-names" export var __name = (target, value) => __defProp(target, 'name', { value, configurable: true }) @@ -185,53 +182,55 @@ func code(isES6 bool) string { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }) } - export var __reExport = (target, module, copyDefault, desc) => { - if (module && typeof module === 'object' || typeof module === 'function') + + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === 'object' || typeof from === 'function') ` // Avoid "let" when not using ES6 if isES6 { text += ` - for (let key of __getOwnPropNames(module)) - if (!__hasOwnProp.call(target, key) && (copyDefault || key !== 'default')) - __defProp(target, key, { get: () => module[key], enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable }) + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }) ` } else { text += ` - for (var keys = __getOwnPropNames(module), i = 0, n = keys.length, key; i < n; i++) { + for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i] - if (!__hasOwnProp.call(target, key) && (copyDefault || key !== 'default')) - __defProp(target, key, { get: (k => module[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable }) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: (k => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }) } ` } text += ` - return target + return to } - // Converts the module from CommonJS to ESM - export var __toESM = (module, isNodeMode) => { - return __reExport(__markAsModule( - __defProp( - module != null ? __create(__getProtoOf(module)) : {}, - 'default', - - // If the importer is not in node compatibility mode and this is an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has been set), then forward - // "default" to the export named "default". Otherwise set "default" to - // "module.exports" for node compatibility. - !isNodeMode && module && module.__esModule - ? { get: () => module.default, enumerable: true } - : { value: module, enumerable: true }) - ), module) - } + export var __reExport = (target, mod) => __copyProps(target, mod, 'default') + + // Converts the module from CommonJS to ESM. When in node mode (i.e. in an + // ".mjs" file, package.json has "type: module", or the "__esModule" export + // in the CommonJS file is falsy or missing), the "default" property is + // overridden to point to the original CommonJS exports object instead. + export var __toESM = (mod, isNodeMode, target) => ( + target = mod != null ? __create(__getProtoOf(mod)) : {}, + __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule + ? __defProp(target, 'default', { value: mod, enumerable: true }) + : target, + mod) + ) // Converts the module from ESM to CommonJS. This clones the input module // object with the addition of a non-enumerable "__esModule" property set // to "true", which overwrites any existing export named "__esModule". - export var __toCommonJS = module => __reExport(__markAsModule({}), module, /* copyDefault */ 1) + export var __toCommonJS = mod => __copyProps(__defProp({}, '__esModule', { value: true }), mod) // For TypeScript decorators // - kind === undefined: class