10

Reduce minified code size by property mangling

 3 years ago
source link: https://lihautan.com/reduce-minified-code-size-by-property-mangling/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

What is Mangling Property

Assume you have the following JavaScript code:

class Human {
  constructor(chewAmount) {
    this.chewAmount = 3;
  }
  eat() {
    for (let amount = 3; amount < this.chewAmount; amount++) {
      this.chew();
    }
  }
  chew() {}
}

function getHumanEating() {
  const lihau = new Human();
  return lihau.eat();
}

Original: 268 Bytes

If you minify this with the default options with Terser, you probably get something like:

class Human {
  constructor(chewAmount) {
    this.chewAmount = 3;
  }
  eat() {
    for (let i = 3; i < this.chewAmount; i++) {
      this.chew();
    }
  }
  chew() {}
}
function getHumanEating() {
  return new Human().eat();
}

207 Bytes (77.2%)

(Usually Terser would compress whitespace too, but for ease of reading, allow me to keep the whitespace)

Your code still behaves the same, even though the variable name has changed.

This behavior of renaming variable name to compress JavaScript code is called Mangle.

Terser has several Mangle options, that allows you to control whether or not to mangle class name, function name, property name, or specify any reserved keywords to not mangle, or should it mangle global variable.

If the above code is written within a ES Module, then probably we wont refer the class Human globally, rather refer it through import, then the name of the class probably does not matter:

// Terser option: { mangle: { module: true } }
class H {
  constructor(chewAmount) {
    this.chewAmount = 3;
  }
  eat() {
    for (let i = 3; i < this.chewAmount; i++) {
      this.chew();
    }
  }
  chew() {}
}
function e() {
  return new H().eat();
}
export { H as Human, e as getHumanEating };

186 Bytes (69.4%)

But can we do better?

Well, if you look at the code, the property named chewAmount takes up 20 characters, which is almost 10% of the code.

If we rename all the property name to 1 character variable, then we would end up with a much smaller code:

class H {
  constructor(t) {
    this.c = 3;
  }
  a() {
    for (let t = 3; t < this.c; t++) this.s();
  }
  s() {}
}
function e() {
  return new H().a();
}
export { H as Human, e as getHumanEating };

107 Bytes (39.9%)

If it ends up with a much smaller bundle, should we rename our property name and method name to a shorter name? And why didn't Terser do this by default?

Should we rename our property name and method name to something short?

No! That would hurt the readability of the code. 😥

Also, what if someone else imports the class Human and wants to use the property chewAmount?

He would have to rename it to human.c instead of human.chewAmount and probably scratching his head everytime he reads his code, wondering what does human.c mean?

Why Terser didn't mangle property name by default?

Because property mangling requires certain assumption on your code, therefore it is marked as very unsafe in the Terser documentation to turn it on entirely.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK