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

Private field transform error in production mode #18540

Open
7 tasks done
mantou132 opened this issue Oct 31, 2024 · 4 comments
Open
7 tasks done

Private field transform error in production mode #18540

mantou132 opened this issue Oct 31, 2024 · 4 comments

Comments

@mantou132
Copy link

mantou132 commented Oct 31, 2024

Describe the bug

The following code does not run correctly in production mode:

const state = () => {};
Object.setPrototypeOf(state, null);

class A {
  #state = state;

  render = () => {
    this.#state();
    return 'Normal';
  };
}
document.body.innerHTML = new A().render();

Reproduction

https://stackblitz.com/edit/vitejs-vite-zzcnuj?file=src%2Fmain.ts

Steps to reproduce

No response

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    vite: ^5.4.10 => 5.4.10

Used Package Manager

npm

Logs

console log:

Uncaught TypeError: v(...).call is not a function

Validations

@mantou132
Copy link
Author

babel typescript esbuild same behavior

@bluwy
Copy link
Member

bluwy commented Oct 31, 2024

This is the generated code by esbuild:

var __defProp = Object.defineProperty;
var __typeError = (msg) => {
  throw TypeError(msg);
};
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);
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var _state;
const state = () => {
};
Object.setPrototypeOf(state, null);
class A {
  constructor() {
    __privateAdd(this, _state, state);
    __publicField(this, "render", () => {
      __privateGet(this, _state).call(this);
      return "Normal";
    });
  }
}
_state = new WeakMap();
document.body.innerHTML = new A().render();

The problem here is that because you have Object.setPrototypeOf(state, null);. The __privateGet(this, _state).call will fail because .call will no longer exist anymore.

If this is happening in babel/typescript/esbuild, then it seems like they've all made the assumption that a function pattern this way won't work. Is there a reason you're doing Object.setPrototypeOf(state, null);?

@mantou132
Copy link
Author

@bluwy I want to have the class members as internal states while being able to update them directly, so I want to clear the object properties

@customElement('my-element')
class MyElement extends GemElement {
  #state = createState({ a: true });

  render() {
    this.#state({ a: false });
    console.log(this.#state.a);
  }
}

@sapphi-red
Copy link
Member

If esbuild generated Function.prototype.call.call(__privateGet(this, _state), this); instead of __privateGet(this, _state).call(this);, the code works.
I think this needs to be worked on esbuild side (also for other transpilers?).

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

No branches or pull requests

3 participants