terser
terser copied to clipboard
Make private class methods inlineable
Bug report or Feature request?
Feature
Version (complete output of terser -V
or specific git commit)
5.10.0
Complete CLI command or minify()
options used
{
module: true,
compress: {},
mangle: {},
output: {},
parse: {},
rename: {},
}
terser
input
export class Minified {
someField;
constructor() {
this.someField = (() => {
return 42;
})();
}
}
export class NotMinified {
someField;
constructor() {
this.someField = this.#privateMethod();
}
#privateMethod() {
return 42;
}
}
terser
output or error
export class Minified{someField;constructor(){this.someField=42}}export class NotMinified{someField;constructor(){this.someField=this.#e()}#e(){return 42}}
Expected result
export class Minified{someField;constructor(){this.someField=42}}export class NotMinified{someField;constructor(){this.someField=42}}
Since there is only 1 call to the private method, it can be inlined, saving a bunch of indirection. Further optimizations can then be applied as well, completely removing the call and setting it to the value.
This is also helpful with event listeners:
export class NotMinified {
#someBoundedListener = this.#someListener.bind(this);
#someListener() {
console.log('listener called');
}
constructor(div) {
div.addEventListener('click', this.#someBoundedListener);
}
}
Which would then be optimized to
export class NotMinified {
constructor(div) {
div.addEventListener('click', () => {console.log('listener called')});
}
}
In addition, I think this:
class X {
constructor(){
if(false){
this.#a();
}
}
#a(){
}
}
var x = new X();
var y = new X();
console.log({x,y})
Could be optimized to:
class o{constructor(){0}}var c=new o,n=new o;console.log({x:c,y:n});
Instead of:
class o{constructor(){0}#o(){}}var c=new o,n=new o;console.log({x:c,y:n});
@jridgewell Could you maybe give an indication how difficult this feature would be? I am interested in contributing this if it isn't too difficult (hopefully!).
This is pretty difficult @TimvdLippe. You would need to create a new compression option, that calls a method that keeps track of which private methods exist in a class (and nested classes), and how many times they're used.
Then you'd need to traverse the class looking for references to the single-use ones to be replaced with the original, and for the original for removal. Interestingly, you would almost accidentally implement inlining for values as well.
Basically you wouldn't be using any of the facilities for scope, variable reference tracking, etc, that exist in the rest of Terser, because private properties aren't kept track of at all.