Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static class fields can’t be tree-shaken away on subsequent compilation #3765

Open
iamakulov opened this issue May 14, 2024 · 0 comments
Open

Comments

@iamakulov
Copy link

iamakulov commented May 14, 2024

Hey Evan,

Thank you for creating and maintaining esbuild!

We @ Framer stumbled upon an issue around static class fields. When you use them, and you’re compiling for ES2021 and below, esbuild produces code that’s not tree-shakeable on a subsequent compilation. This is relevant e.g. when you’re a library author and are distributing the library as a bundle.

Steps to reproduce

  • Create my-library.js with the following code:

    export class Navigation {
      state = defaultState()
    
      static defaultProps = {
        enabled: true,
      }
    
      static contextType = NavigationCallbackContext
    }
  • Bundle the library with { target: "es2019" } into my-library-compiled.js. Observe that the library is compiled down 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);
    export class Navigation {
      constructor() {
        __publicField(this, "state", defaultState());
      }
    }
    __publicField(Navigation, "defaultProps", {
      enabled: true
    });
    __publicField(Navigation, "contextType", NavigationCallbackContext);
  • Now, import the compiled library from another file (say, my-app.js):

    import {} from "./my-library-compiled.js"
  • Bundle that file (using esbuild, webpack, etc – doesn’t matter). Observe that the app bundle includes Navigation, even though it’s not used.

Actual result

Any classes that use static fields in the library can’t be tree-shaken away due to top-level __publicField setters.

Expected result

esbuild compiles classes with static fields down to something like this:

export class Navigation {
  state = defaultState()

  static defaultProps = {
    enabled: true,
  }

  static contextType = NavigationCallbackContext
}

export var Navigation = /* @__PURE__ */ (() => {
  class Navigation {
    constructor() {
      __publicField(this, "state", defaultState());
    }
  }
  
  __publicField(Navigation, "defaultProps", {
    enabled: true
  });
  
  __publicField(Navigation, "contextType", NavigationCallbackContext);
  
  return Navigation;
})()

which allows Navigation to be tree-shaken away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant