-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Class renaming breaks certain patterns #510
Comments
Just having a look, it seems like the solution would be somewhere in the linker or renamer. Perhaps it's possible (to my naïve eyes) for class names to (optionally) be considered reserved names via This looks like it could be done by looking at the symbol kind, or alternatively adding I'm sure this is probably pretty obvious (and quite possibly obviously incorrect) if you're familiar with it, but since esbuild is an important item for us I thought I'd have a look and point in the general direction. |
Forcing the name to not change may end up corrupting the build because two symbols from different files can have the same name, and these names will collide and either cause a syntax error or silently shadow the previous name if they end up being hoisted into the same scope. So this change is more complicated than just keeping the names the same. I think this feature could be made to behave similar to direct |
The On the collision problem, perhaps the reserved name a.) occur only with class name declarations; and b.) raised an error on collision. By illustration, if the following are bundled. a.tsclass Hello {} // becomes a reserved name b.tsconst Hello // renamed to Hello2 c.tsclass Hello {} // throws error: duplicate reserved class name Does this pattern address the hoisting collision problem? The problem is limited to two class declarations of he same name, and in that case an error could be thrown for this. |
Actually I think the easiest way to solve this would be to have an option that injects code which assigns to the // original.js
class Hello {}
function hello() {} // generated.js
let __name = (obj, value) => Object.defineProperty(obj, 'name', {value, configurable: true});
class Hello2 {}
__name(Hello2, 'Hello');
function hello2() {}
__name(hello2, 'hello'); That wouldn't disable tree shaking and would let these symbols still be minified. |
I was just thinking in that direction, too. That certainly feels like the least-invasive option. I dare say, "correct". |
... the only caveat I have is that this has been a known problem of minification / mangling for a very long time, so I wonder why nobody else had done it. My only guess is that it will not work with IE. |
What makes the late-rename necessary? Not sure about TS, but in JS, |
Here's the case I'm worried about. Imagine two files: // a.js
import {Hello as Foo} from './b'
export class Hello { foo = new Foo } // b.js
import {Hello as Bar} from './a'
export class Hello { bar = new Bar } It would be bad if esbuild's scope hoisting pass compiled that to something like this: // a.js
let Hello = class Hello { foo = new Hello2 }
// b.js
let Hello2 = class Hello { bar = new Hello } The second class stored in the variable Another issue is that people are going to want this to work with functions too, and there the same approach doesn't apply because function declarations are hoisted while variable declarations and function expressions aren't. Hoisting can be mitigated to some extent by reordering statements but doing that across files starts to get complex. Basically assigning to |
Makes sense. I can see now how it would end up adding more complexity / special cases to consider — thanks for explaining. |
@evanw Just to confirm, the |
Fantastic, thanks @evanw ! |
I can open a different issue for this if it makes more sense, but I just hit the following problem (reproduced here more minimally) and it seems related to what’s been discussed above: // In:
class Foo {
static Bar = Foo;
}
// Out:
var Foo = class {
static Bar = Foo;
}; The output isn’t equivalent and will throw a ReferenceError that the input doesn’t. |
Yeah sorry about that. I discovered this myself yesterday. It's already fixed and is going out with the next release: https://github.com/evanw/esbuild/blob/2001dff446c016612f4043c8ff8b7cb1bf69ed5e/CHANGELOG.md#unreleased. It's actually not related to this issue. It's related to issue #478 instead. |
Awesome! And wow, that’s some issue ... it’s like tooling dev creepypasta. |
Anyone coming here from Google, the option |
It's not uncommon for code to use the class name constructor for certain patterns i.e.
elsewhere
When the esbuild bundler hits a conflicting class name it appends a number, which breaks the pattern.
There are several potential ways to fix this, including (purely for illustration):
--no-class-rename
) that throws an error rather than adding a number to the class name. (For obvious reasons, this--no-class-rename
would also ideally prevent class name mangling during minification).This is blocking our project from using esbuild, and would also break one of the patterns in the TKO project that I maintain (a successor to/built on knockout.js).
The text was updated successfully, but these errors were encountered: