Tuesday, July 31, 2012

Enterprise-class Javascript, part II


My previous post was about modularity and dependency management using AMD based RequireJS. While modularity and dependency management form a basis for re-usable software development, it's not all. In the world of Web-based applications there's one special feature; if you application runs on browser it means all your HTML, CSS and Javascript files must be accessible in source format. Especially with Javascript it means your precious source code doensn't have any theft-protection. Legal or not, but anyhow the source code can be stolen just like that and I know people are doing it a lot. Now you may think "thank god we only allow clients who have signed on", but it really means "only signed-on clients can steel your source code". How do you control which of your clients has stolen your potentially valuable source code? If you don't care, how about donating all your server side code, too? On the other hand, most Javascript files I've seen are such big piles of steaming shit that nobody actually wants them even for free (wait for episode 3 of this series). I've contributed those piles too before I decided to get some real understanding about Javascript. And even if you don't mind about your source code being stolen, having your source code accessible and in readable format also opens it security vulnerability. For example, one can check from source code your field validation rules and use that information to enter illegal data.

So, if this is a real problem, somebody must have solved it already, right? Yes, it has been solved but it's not used as much as one would expect. Since I'm still in the middle of studying RequireJS, right now I'm suggesting Google's Closure Compiler. You can find a web version here. Google Closure Compiler will optimize and mangle your code. One of the episodes to come will dive into optimizations, but for now we are just fine with the mangling. I use my "fancy" memory game  as a sample. It contains just a couple of placeholder divs and mangled, optimized Javascript code. It's not optimized as much as it could, but it's a good start. You can find the associated Javascript content here.

Now a simple function like this:

function funnel( n,fn ) {
return function( ) {
if( --n == 0 )
fn.apply( null,arguments );
};
}

has become this:

function l(b,a){return function(){--b==0&&a.apply(null,arguments)}}

That's not very far from the original, so let's try a little bit more complex function like this:

function animateText( $objects,text,then,delay,classesToRemove,classesToAdd ) {
if( delay != undefined )
$objects.delay( delay );
$objects.fadeOut( delayInTurning,function( ) {
var $this = $(this);
$this.text( text );
if( classesToRemove != undefined )
$.each( classesToRemove,function( idx,cssClass ) {
$this.removeClass( cssClass );
} );
if( classesToAdd != undefined )
$.each( classesToAdd,function( idx,cssClass ) {
$this.addClass( cssClass );
} );
} ).fadeIn( delayInTurning,then );
}

It becomes this:

function n(b,a,c,f,d,e){f!=h&&b.delay(f);b.fadeOut(p,function(){var b=$(this);b.text(a);d!=h&&$.each(d,function(a,c){b.removeClass(c)});e!=h&&$.each(e,function(a,c){b.addClass(c)})}).fadeIn(p,c)}

While you have all the functionality in the mangled version, you understand it? Can you make any changes to it? What if you have lots of functions which all look like this? At least it makes a lot harder to understand and maintain this kind of code. How about reversing the mangling, reverting original sources back with another tool? Is it possible? If you put a donkey to the mincer, can you reincarnate the donkey by putting the minced meat to another machine?

No comments:

Post a Comment