Showing posts with label jsmake. Show all posts
Showing posts with label jsmake. Show all posts

Wednesday, September 22, 2010

Debugging anonymous functions in Javascript.

Javascript allows you to create function without name. That's why we name them (oxymoron), anonymous functions. Almost used everywhere, this kind of function can become a real nightmare to debug. We will see what is the problem and how to solve it.

Anonymous functions


Let's first see what is an anonymous function by looking at some code:

var myObject = {
    doSomething:function () {
       console.loh("my message");
   }
};

document.body.onclick=function(){
    myObject.doSomething();
}

The code in it self does not do much...
But you can see that we define functions that do not have a name.
They are assigned to a property.

Notice that:
var myFunc = function() {

}
function myFunc() {

}

is different in the timing you will be able to call these functions.
For example:

myFunc();
var myFunc = function() {

}

will fail but not:
myFunc();
function myFunc() {

}

Functions are parsed first and are available, whatever the order you write your code in. (Not true in the console of Firebug though.)
By the way, did you see the typo? console.loh() instead of console.log().

If you run this script, you will get a nice error that you can look in Firebug, Firefox:

onclick()
(?)()

Not helping...
If you have hundreds of line of javascript code, I can tell you that it may take some time to get to the error...

So how can we handle this?

Name your anonymous functions

ok,so what's the deal? name your anonymous functions, oxymoron, here, oxymoron there...

It's easy, give a name to your anonymous functions:

var myObject = {
    doSomething:function $_doSomething() {
       console.loh();
   }
};

document.body.onclick=function $_bodyClick(){
    myObject.doSomething();
}


Prefixing all the anonymous functions with $_ is just a convention
that is going to help in a few seconds.
Traced in Firebug, you get:

$_doSomething()
$_bodyClick()

A little bit nicer than the cryptic first output!

But naming anonymous functions for the sole purpose of debugging is going to add unnecessary bytes right??
Indeed, we should name them for debugging and erase their name for the live version.
But this is too much of hassle and nobody will do it unless...

Javascript Preprocessor at the rescue.

There are many preprocessors out there that allows you to simplify the build process of your javascript files.
One of them,jsmake (which I've also written-sorry), allows you to automatically name all your anonymous functions or do the opposite, remove their names.

In order to remove all the anonymous function names, you will need to prefix them with $_. If you let the preprocessor name them instead of doing it by hand, it will prefix them with $_ so that you can remove them again very easily via the same preprocessor!


A simple example will be:

var testing = function () {
    return true;
}
var myObject = {
    doSomething:function () {
       console.log();
   }
};
document.body.onclick=function(){
    myObject.doSomething();
}
document.body.addEventListener('click',function(e){
    var object= {};
    object.testing = function() {
        return true;
    }
});

Once preprocessed, you get:
var testing = function $_testing1 () {
    return true;
}
var myObject = {
    doSomething : function $_doSomething1 () {
       console.log();
   }
};
document.body.onclick = function $_onclick1 (){
    myObject.doSomething();
}
document.body.addEventListener('click',function $_anon1(e){
    var object= {};
    object.testing = function $_testing2 () {
        return true;
    }
});

You can read more about this here.
Don't hesitate to introduce other preprocessors that do the same thing or offer even more functionality!

Friday, July 9, 2010

jsmake: a simple javascript preprocessor in perl

In the previous post I listed some javascript preprocessors you could find out there...
But could not find any written in perl...
And could not find a preprocessor that could handle package dependencies...
Therefore,I've taken a day to hack a command line utility to use as a basic preprocessor for javascript.
Only tested on my mac, it's a dirty, huge perl file but it might help some people out there until there's a real project to build a javascript preprocessor in perl.

Functionality

This utility can:

- compress the javascript files with 3 different algorithms:

Javascript::Mini
Javascript::Packer
Google online closure application

- load and merge files in order of dependency:

jsmake follows package rules used by perl or actionscript language.
It transpose the package name into a folder tree. Therefore:

Core.Util.Array

is understood as Core/Util/Array.js.

You can specify the dependeny at the very first line of your javascript file in a comment as follow:

/*!require: Core.Util.String,Core.Util.Queue */

jsmake will load all the dependencies in all the files in the right order.

- parse the javascript source file for some directives.

ifdef, ifndef, end, define are understood:

/*@ifdef DEBUG */
console.log("debug mode");
/*@end */


/*@ifndef DEBUG */
console.log("not in debug mode");
/*@end */

or if you like # better:


/*#ifndef DEBUG */
console.log("not in debug mode");
/*#end */

/*@define VERSION 1.06 */

How to use

on the terminal, just type:

$ jsmake

if you do not need any options just make the file executable.

There are obviously command line options:

input

$ jsmake -input ../lib

This tells where to look for the javascript to be merged/preprocessed/smashed.

output

$ jsmake -output ../src/merged.js

This tells where to output the final merged output.

compression

$ jsmake -compression name


Example:
$ jsmake -compression mini

This tells what kind of compression it should use.
There are 3 different compressors for now:
  • packer
  • mini
  • closure
Closure use google online closure service with the least aggressive algorithm.
So... you just need to be connected to the internet to use this one.
packer and mini requires perl modules to be installed, respectively JavaScript::Packer and JavaScript::Minifier.

Using the compression will output 2 files:
the one uncompressed and the one compressed prefixed with the name of the compression type, so it might be output.js and closure-output.js

packages

$ jsmake -packages name separated by a space

Example:
$ jsmake -packages Core.DOM Core.Util.String

If you do not specify a package jsmake will merge all the files that contain the !require: directive.
By specifying the package name,jsmake will only merge the file necessary for this package to work as defined in your dependencies.

vars

$ jsmake -vars name separated by a space

Example:
$ jsmake -vars DEBUG STRICT_MODE

By specifying the name of some variables, you will make them come true.
Therefore all the ifdef or ifndef will be stripped down accordingly.
if you want a STRICT_MODE but no DEBUG messages, you will write:
$ jsmake -vars STRICT_MODE

define

$ jsmake -define name=value variable name=value

Example:
$ jsmake -define VERSION=6.01 AUTHOR=myself

vars allows you to overwrite the one inline in your javascript file.
So if you define in your javascript /#define VERSION 3.01 / but at the command line
set the variable to 6.01, the final output will be 6.01
Will look into merging vars and define functionality into one as it is confusing...

That's it!!

so if we go for a full option set up, you can get:

$ jsmake -input ../lib -output ../src/merged.js -packages Core.DOM Core.Util.String -vars DEBUG -define VERSION=6.12 AUTHOR=myself -compression mini

This will create two files merged.js and mini-merged.js compressed, cleaned out and with all the dependencies.

Download & Doc

http://code.google.com/p/jsmake-preprocessor/

Hope this is useful too somebody and that you won't be too hard on my perl capacities. Comment to improve the code welcome!