evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
37.93k stars 1.13k forks source link

[BUG] `export {trackingModuleNamespaceExoticObjects}` should have tree-shake optimization #3081

Open loynoir opened 1 year ago

loynoir commented 1 year ago

Description

esbuild is not keep tracking of module namespace exotic objects to have tree-shake optimization.

Useful Link

module namespace exotic objects

https://github.com/evanw/esbuild/issues/3077#issuecomment-1518725003

One important difference between normal JavaScript objects and the objects that you get when you import a namespace (called module namespace exotic objects in the JavaScript specification) is that module objects don't allow you to mutate their properties.

Usage

import * as TypeRegistry from './TypeRegistry.mjs'

function someFn() {
  TypeRegistry.Clear()
}

Thus, user get a dot property like syntax with tree-shake optimization.

Reproduce

==> user.mts <==
import { someFn, TypeRegistry } from './typebox.mjs'

TypeRegistry.Clear()
// someFn()

==> typebox.mts <==
import * as TypeRegistry from './TypeRegistry.mjs'

function someFn() {
  TypeRegistry.Clear()
}

export { someFn, TypeRegistry }

==> TypeRegistry.mts <==
const map = new Map<string, unknown>()

export function Entries() {
  return new Map(map)
}

export function Clear() {
  return map.clear()
}
$ npm exec -- esbuild --format=esm --bundle ./user.mts

Actual

var __defProp = Object.defineProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};

// TypeRegistry.mts
var TypeRegistry_exports = {};
__export(TypeRegistry_exports, {
  Clear: () => Clear,
  Entries: () => Entries
});
var map = /* @__PURE__ */ new Map();
function Entries() {
  return new Map(map);
}
function Clear() {
  return map.clear();
}

// user.mts
TypeRegistry_exports.Clear();

Expected

// TypeRegistry.mts
var map = /* @__PURE__ */ new Map();
function Clear() {
  return map.clear();
}

// user.mts
Clear();

Like when user.mts

import { someFn, TypeRegistry } from './typebox.mjs'

// TypeRegistry.Clear()
someFn()

Got

// TypeRegistry.mts
var map = /* @__PURE__ */ new Map();
function Clear() {
  return map.clear();
}

// typebox.mts
function someFn() {
  Clear();
}

// user.mts
someFn();
Conaclos commented 1 year ago

I think that it is a duplicate of #1420.

loynoir commented 1 year ago

https://tc39.es/ecma262/#sec-module-namespace-exotic-objects

@Conaclos

Not sure about the definition.

Maybe it is duplicated.

Maybe it is a stricter subset of your issue there.

I have no idea, so, I left it opened.