esbuild 0.13.11
-
Implement class static blocks (#1558)
This release adds support for a new upcoming JavaScript feature called class static blocks that lets you evaluate code inside of a class body. It looks like this:
class Foo { static { this.foo = 123 } }This can be useful when you want to use
try/catchor access private#namefields during class initialization. Doing that without this feature is quite hacky and basically involves creating temporary static fields containing immediately-invoked functions and then deleting the fields after class initialization. Static blocks are much more ergonomic and avoid performance loss due todeletechanging the object shape.Static blocks are transformed for older browsers by moving the static block outside of the class body and into an immediately invoked arrow function after the class definition:
// The transformed version of the example code above const _Foo = class { }; let Foo = _Foo; (() => { _Foo.foo = 123; })();In case you're wondering, the additional
letvariable is to guard against the potential reassignment ofFooduring evaluation such as what happens below. The value ofthismust be bound to the original class, not to the current value ofFoo:let bar class Foo { static { bar = () => this } } Foo = null console.log(bar()) // This should not be "null" -
Fix issues with
superproperty accessesCode containing
superproperty accesses may need to be transformed even when they are supported. For example, in ES6asyncmethods are unsupported whilesuperproperties are supported. Anasyncmethod containingsuperproperty accesses requires those uses ofsuperto be transformed (theasyncfunction is transformed into a nested generator function and thesuperkeyword cannot be used inside nested functions).Previously esbuild transformed
superproperty accesses into a function call that returned the corresponding property. However, this was incorrect for uses ofsuperthat write to the inherited setter since a function call is not a valid assignment target. This release fixes writing to asuperproperty:// Original code class Base { set foo(x) { console.log('set foo to', x) } } class Derived extends Base { async bar() { super.foo = 123 } } new Derived().bar() // Old output with --target=es6 (contains a syntax error) class Base { set foo(x) { console.log("set foo to", x); } } class Derived extends Base { bar() { var __super = (key) => super[key]; return __async(this, null, function* () { __super("foo") = 123; }); } } new Derived().bar(); // New output with --target=es6 (works correctly) class Base { set foo(x) { console.log("set foo to", x); } } class Derived extends Base { bar() { var __superSet = (key, value) => super[key] = value; return __async(this, null, function* () { __superSet("foo", 123); }); } } new Derived().bar();All known edge cases for assignment to a
superproperty should now be covered including destructuring assignment and using the unary assignment operators with BigInts.In addition, this release also fixes a bug where a
staticclass field containing asuperproperty access was not transformed when it was moved outside of the class body, which can happen whenstaticclass fields aren't supported.// Original code class Base { static get foo() { return 123 } } class Derived extends Base { static bar = super.foo } // Old output with --target=es6 (contains a syntax error) class Base { static get foo() { return 123; } } class Derived extends Base { } __publicField(Derived, "bar", super.foo); // New output with --target=es6 (works correctly) class Base { static get foo() { return 123; } } const _Derived = class extends Base { }; let Derived = _Derived; __publicField(Derived, "bar", __superStaticGet(_Derived, "foo"));All known edge cases for
superinsidestaticclass fields should be handled including accessingsuperafter prototype reassignment of the enclosing class object.