How to minify private methods in a TypeScript class?

przemyslawjanbeigert

Przemyslaw Jan Beigert

Posted on March 6, 2023

How to minify private methods in a TypeScript class?

Introduction

As you may notice during minification your long and descriptive variable names are changed into e.g.: "a", "rd", "xd". However, when you minify class names of methods stay the same:

class Cls {
  method() {
  }
}

const cls = new Cls();
cls.method();
Enter fullscreen mode Exit fullscreen mode

Will be compiled into

"use strict";(()=>{var c=class{method(){}},e=new c;e.method();})();
Enter fullscreen mode Exit fullscreen mode

Is logical because method has been used in other scripts. But what about private methods?

class Cls {
  public publicMethod() {
    this.privateMethod()
  }
  private privateMethod() {}
}

const cls = new Cls();
cls.publicMethod();
Enter fullscreen mode Exit fullscreen mode

This code with be compiled into:

"use strict";(()=>{var t=class{publicMethod(){this.privateMethod()}privateMethod(){}},e=new t;e.publicMethod();})();
Enter fullscreen mode Exit fullscreen mode

The private method stays the same. Is logical cause code is firstly transpile into JavaScript and then minified. During transpiration information about method privacy will be lost.

Terser

Terser is JavaScript compressor that can minified specific method names.

// terser.config.js
const fs = require('fs');
const terser = require('terser');

(async () => {
    const file = fs.readFileSync('index.js', 'utf8')
    const {code} = await terser.minify(file, {
        mangle: {
            properties: {
                regex: `^(privateMethod)$`,
            },
        },
    });
    fs.writeFileSync('index.js', code)
})();
Enter fullscreen mode Exit fullscreen mode

This code will create something like this:

"use strict";(new class{publicMethod(){this.t()}t(){}}).publicMethod();
Enter fullscreen mode Exit fullscreen mode

Great success? Not yet. We can not manually paste every private method to the config file.

Find all private method

We can use bash to find all names of private methods.

  1. Print all TS files
cat src/**/*.ts
Enter fullscreen mode Exit fullscreen mode
  1. Filter lines by pattern private methodName(...) {
grep -E "^  private (.*?)\("
Enter fullscreen mode Exit fullscreen mode

You can use prettier to be sure that all methods are formatted in the same way.

  1. Map lines like with private methodsName( into methodName by
awk '{split($2,a,"("); print a[1]}'
Enter fullscreen mode Exit fullscreen mode
  1. Join each method with | separator by:
tr '\n' '|'
Enter fullscreen mode Exit fullscreen mode
  1. Merge it with bash pipes:
cat src/**/*.ts | egrep "  private (.*?)\(" | awk '{split($2,a,"("); print a[1]}' | tr '\n' '|'
Enter fullscreen mode Exit fullscreen mode

The output should looks like this: privateMethod|privateMethod1|privateMethod2. It exactly the same that what we can paste to regex in the terser.config.

Fix collision

Unfortunately is public method will have the same name like a private one, both will be minified. How to fix that? Use previous script to find all public methods then just filter in out in the terser.config.js

const methodsToMinify = privateMethods
  .split('|')
  .filter(item => !publicMethods.includes(item))
  .join('|');
Enter fullscreen mode Exit fullscreen mode

Result

In my project helped me reduce bundle size by around 11%. It doesn't sound impressive, however applying this solution is relatively fast

💖 💪 🙅 🚩
przemyslawjanbeigert
Przemyslaw Jan Beigert

Posted on March 6, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related