esbuild: Class renaming breaks certain patterns
It’s not uncommon for code to use the class name constructor for certain patterns i.e.
const registry: Record<string, WebComponent> = {}
class WebComponent {
static register (registrationID = this.constructor.name) { register[registryID] = this }
static load (registryID: string) { return register[registryID] }
}
class ComponentA extends WebComponent {}
ComponentA.register()
elsewhere
const ComponentA = '123'
WebComponent.load('ComponentA') // fails b/c it's "ComponentA2"
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):
- an optional check (e.g.
--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). - giving priority to class names not being renamed (i.e. maintaining its original name) over other symbols when there’s a collision
- including some source-code comment that specifies that the symbol not be renamed
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).
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 2
- Comments: 16 (4 by maintainers)
Anyone coming here from Google, the option
--keep-names
has been added since this was closed I think. It seems to have solved the problem I had that led me here.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.
Here’s the case I’m worried about. Imagine two files:
It would be bad if esbuild’s scope hoisting pass compiled that to something like this:
The second class stored in the variable
Hello2
would accidentally setbar
to an instance of the class from fileb.js
instead of the class from filea.js
because the use of a class expression introduces a new symbolHello
that shadows the top-level symbolHello
. It might be possible to get this to work with enough renaming magic but it seems more complicated.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
name
is the simplest solution.