esbuild icon indicating copy to clipboard operation
esbuild copied to clipboard

Private properties are lowered when combine with static properties

Open bakura10 opened this issue 3 years ago • 4 comments

Hi,

I have initially reported that in #2158 but I thought it may be useful to report it as an individual issue as the original issue is a bit different.

As of today, even when setting esnext as a target, esbuild improperly lower private syntax when one class contains a static method and bundling is enabled.

For instance, this:

export class Test {
  #foo = 5;
}

is properly transformed to:

// js/foo.js
var Test = class {
  #foo = 5;
};

export {
  Test
};

However, as soon as a static property enter into the game, everything is lowered, although esnext should support both syntax natively:

export class Test {
  static bar = 1;
  #foo = 5;
}

Is transformed to:

var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
var __privateAdd = (obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};

// js/foo.js
var _foo;
var Test = class {
  constructor() {
    __privateAdd(this, _foo, 5);
  }
};
_foo = new WeakMap();
__publicField(Test, "bar", 1);
export {
  Test
};

bakura10 avatar Jul 25 '22 05:07 bakura10

Reproduction Link, it only occurs when bundle: true.

hyrious avatar Jul 25 '22 06:07 hyrious

Yes, that's true. This is likely not a bug but a limitation of esbuild's single-pass design. See this comment for an example.

evanw avatar Jul 25 '22 12:07 evanw

Is there any workaround for this ? Maybe could we pass an option to instruct Esbuild we are not using static field with new ?

bakura10 avatar Jul 25 '22 14:07 bakura10

I've just encountered this strange behaviour. Why doing var Test = class {} ? (as class Test{}can be hidden within a (function () {})() ? Why calling an external __publicField() where it could be only Test.bar = 1 ?

guiled avatar Sep 11 '22 22:09 guiled

I know it's a bummer but a workaround seems to be go old school

export class Test {
  #foo = 5;
}
Test.bar = 1;

https://hyrious.me/esbuild-repl/?version=0.14.50&mode=build&modules=%5B%5B%22main.js%22%2C%22export+class+Test+%7B%5Cn++%23foo+%3D+5%3B%5Cn%7D%5CnTest.bar+%3D+1%3B%22%2C1%5D%5D&buildOptions=%7B%22bundle%22%3Atrue%7D

luwes avatar Mar 25 '23 00:03 luwes