Gordon Williams
Gordon Williams

Reputation: 1886

How to minify a single module

I'm trying to minify node.js style modules for Espruino (a microcontroller that runs JavaScript). These modules often have hidden internal constants and convenience functions defined, and I want to collapse those down.

As a very contrived example, let's say I have:

var C = {
CONST1 : 32,
CONST2 : 64
};

function Foo() {
}

Foo.prototype.C = {
  ONE : 1,
  TWO : 2
};

function doStuff(x) { 
  return x+1;
}

Foo.prototype.getConst = function (x) {
  return doStuff((x==this.C.ONE) ? C.CONST1 : C.CONST2);
}

exports.foo = function() { return new Foo(); };

I'd like to minify this down to:

function Foo(){}Foo.prototype.C={ONE:1,TWO:2};Foo.prototype.getConst=function(a){return a==this.C.ONE?33:65};exports.foo=function(){return new Foo};

However currently I'm using the closure compiler online service and this will either do a simple minification in 'Simple' mode (not folding in the hidden C and doStuff):

var C={CONST1:32,CONST2:64};function Foo(){}Foo.prototype.C={ONE:1,TWO:2};function doStuff(a){return a+1}Foo.prototype.getConst=function(a){return doStuff(a==this.C.ONE?C.CONST1:C.CONST2)};exports.foo=function(){return new Foo};

or on 'Advanced' it'll go mad, rename the functions and remove everything:

function a(){}exports.a=function(){return new a};

So how do I tell it to keep all children of exports and everything referenced by those children intact (with the same names)?

Wrapping the code in:

(function(){
  ...
})();

Has the desired effect, but then I have to strip out (function(){ and })(); from what is returned, which seems like a bit of a cludge.

Or is there another minifier (it doesn't have to be online) that would handle this correctly?

Upvotes: 0

Views: 195

Answers (2)

Gordon Williams
Gordon Williams

Reputation: 1886

Well, it looks like the only solution was to do as I'd originally mentioned in the question, regardless of how much of a cludge it was:

Wrap the code in:

(function(){
  ...
})();

Pass it to the closure compiler with SIMPLE_OPTIMIZATIONS, and then strip out (function(){ and })(); from the beginning and end of the response.

This allows the closure compiler to do constant folding, to completely remove the C array in a lot of cases, and to really reduce the code size.

So with the example above, instead of:

var C={CONST1:32,CONST2:64};function Foo(){}Foo.prototype.C={ONE:1,TWO:2};function doStuff(a){return a+1}Foo.prototype.getConst=function(a){return doStuff(a==this.C.ONE?C.CONST1:C.CONST2)};exports.foo=function(){return new Foo};

I get:

function a(){}a.prototype.C={ONE:1,TWO:2};a.prototype.getConst=function(a){return(a==this.C.ONE?32:64)+1};exports.foo=function(){return new a}}

Which is a pretty significant saving in not only code size, but also the memory needed to execute that code.

Upvotes: 0

alex
alex

Reputation: 12275

You can minify local names with uglifyjs -m toplevel.

As for folding, I believe it's usually not possible in javascript. In your particular case it'll work, but general code is usually too complex for static analyzer to do tricks like that.

Upvotes: 1

Related Questions