Tuesday, 6 November 2012

Problem with eval() and minification

After using Cassette for minification, I found a script error when I built the site in release which went away in debug. Of course, in debug, the minification is occuring and what was happening related to the following Microsoft code:
function ValidatorOnLoad() {
    if (typeof(Page_Validators) == "undefined")
        return;
    var i;
    var val;
    for (i = 0; i < Page_Validators.length; i++) {
        val = Page_Validators[i];
        if (typeof(val.evaluationfunction) == "string") {
            eval("val.evaluationfunction = " + val.evaluationfunction + ";");
        }
What is happening here is that because of the overloaded and confusing use of the evaluationfunction property, the code is executed using eval(). The problem during minification is that the variable val is renamed to something smaller, let's say 'n' and the code effectively becomes:
function ValidatorOnLoad() {
    if (typeof(Page_Validators) == "undefined")
        return;
    var i;
    var n;
    for (i = 0; i < Page_Validators.length; i++) {
        n = Page_Validators[i];
        if (typeof(n.evaluationfunction) == "string") {
            eval("val.evaluationfunction = " + n.evaluationfunction + ";");
        }
The val inside the quotes is (understandably) untouched and the error occurs because val is undefined. I tried various things like getting the MS minifier to use one of its properties which says to ignore the minification of functions that contain eval() but this didn't work, I then changed to use the Yahoo minifier (YUI Compressor) to achieve the same thing but still no dice. It looked the function was sort of left alone but some changes were still made which broke it. In the end I had to rewrite the eval statement to work in a way that was minifier friendly. I ended up with this:
function EvaluateStringFunction(func)
{
    var t;eval("t = "+func+";");return t;
}
function ValidatorOnLoad() {
    if (typeof(Page_Validators) == "undefined")
        return;
    var i;
    var val;
    for (i = 0; i < Page_Validators.length; i++) {
        val = Page_Validators[i];
        if (typeof(val.evaluationfunction) == "string") {
            val.evaluationfunction = EvaluateStringFunction(val.evaluationfunction);
        }
What you can see is that by returning the result of the evaluation via a function return, it avoids the ambiguity of the use of val.evaluation function and this is minifier friendly. It seems that the minifier will not rename the var inside the new function which means it should always match the t which is assigned to in EvaluateStringFunction().
Post a Comment