Class.name always 'e' for every class after uglify / webpack for production
Asked Answered
K

3

6

I have an app which is working great in development enviroment but it is not working in production, which is caused by uglify (I think so)

I have a data which user builds and I am saving that either to file or to LocalStorage (json in both cases so doesn't matter).

The structure is built from 3 type of nodes. I have implemented property in the base class ( all inherit from one class): type =this.constructor.name and it is working great in development. When I load the app and read the cache, I go through the JSON and rebuild objects using switch (obj.type) case class1.name... etc. It is working well.

However, when I build for production, when I call class1.name or class2.name or class3.name it all returns e which makes it impossible to restore proper objects...

I do not think it is framework specific issue, but if someone would need to know I build using VueJS with Quasar Framework.

Any ideas?

Knut answered 10/5, 2018 at 7:13 Comment(0)
M
11

constructor.name or any other function name property should never be relied in client-side JavaScript, exactly because minification is a must in production environment, and functions with meaningful names become one-letter named functions. e is a common name for a function minified with UglifyJS. This is the reason why uglified JS file has much lesser footprint than unminified file.

If function/class names are used for anything but debugging, they should be explicitly specified as static properties. Since name cannot be redefined in some engines, non-standard displayName (can also be useful for debugging) or any other property name can be used:

class Foo {
  static get id() { return 'Foo' }
  ...
}

Or:

class Foo {
  ...
}
Foo.id = 'Foo';
Mcafee answered 10/5, 2018 at 7:44 Comment(4)
Can you make uglifyJS spit out mangled, but unique class names? Those would be much shorted, but still usable.Metagnathous
No, afaik. The idea looks interesting but it would have limited uses. Names cannot be used for anything but debugging. Even if identifiers are unique, this doesn't prevent a class from becoming b in another build.Mcafee
Not necessarily. I am using "name" to determine what kind of authorization method the user used along with the token. When reloading the page I will use that string to initialize the correct class. As long as they are unique, it's fine. It can pose a problem between builds if the identifiers change, that's right, but not catastrophic - the user just needs to log in again.Metagnathous
@ÁkosVandra-Meyer you can actually ensure the classes has mangled but unique names. Check out my answer that shows the idea.Unchancy
T
1

For whoever comes after

Webpack uses UglifyJS to compress and hide aspects of your code (referred to as 'mangle'), with regards to your question specifically, it transforms all your classes to e, you have to specific either in your webpack config or cli to not do this if you'd like to preserve your classnames and/or function names.

You can disable this behavior by removing the minimization or creating your own optimization instance as shown here

Tsarism answered 11/3, 2019 at 17:33 Comment(1)
Can you make uglifyJS spit out mangled, but unique class names? Those would be much shorted, but still usable.Metagnathous
U
1

Depending on your goal you can also use the below approach. In my case I just needed to be able to distinguish between class types so the below was sufficient:

class MyClass {
    constructor(){
        this.createClassId()
    }
    createClassId(){
        if(!this.constructor.prototype._customClassId){
        this.constructor.prototype._customClassId = uuidv4() //you choose what you want this _customClassId to be. Or have a look at nanoId which can produce shorter names
    }
}

then new MyClass()._customClassId would be the same for all instances of the same class. And if, for example, you inherit from MyClass, the subclasses will have the same _customClassId month all instances of subclasses but it will be different from what the parent class holds.

If you need to control what exactly _customClassId should be for each class, you can do it as well, though it will require a bit more setup using inheritance like below:

class MyBaseClass {
    constructor(){
        this.createClassId()
    }
    createClassId(){
        if(!this.constructor.prototype._customClassId){
        this.constructor.prototype._customClassId = this.getCustomClassName() //you choose what you want this _customClassId to be. Or have a look at nanoId which can produce shorter names
    }

    getCustomClassName(){
        throw new Error("Make sure to implement 'getCustomClassName' in your subclass")
    }

}

Then you can extend every class where you need to access their classType/className from this MyBaseClass and override getCustomClassName providing your value.

Unchancy answered 1/1, 2022 at 19:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.