Search code examples
asp.net-mvcminifybundling-and-minificationwebgrease

System.Web.Optimization.JsMinify produces invalid JavaScript


I am using System.Web.Optimization v1.3 in what I believe is a standard configuration, to bundle and minify the JavaScript and CSS files in an MVC 5 web application. For the most part, this works very well, but I have discovered a case where JavaScript is corrupted by the minification process.

Here is a simplified version of what was originally an AngularJS input validation directive:

var myApp;
(function (myApp) {
    myApp.module.directive("validator", [
        function () {
            return {
                link: function (scope, element) {
                    var validators = [
                        { signal: "required", message: "Please enter a value", value: null },
                        { signal: "email", message: "Please enter a valid email address", value: null }
                    ];
                    $("input", element).on("blur", function () {
                        for (var i in validators) {
                            var validator = validators[i];
                            if (scope.$parent.form[scope.modelName].$error[validator.signal]) {
                                element.removeClass("has-success");
                                scope.errorMessage = myApp.Utility.formatString(validator.message, eval(validator.value));
                                break;
                            }
                        }
                    });
                }
            };
        }
    ]);
})(myApp || (myApp = {}));

Although the above code no longer does anything useful (because it has been trimmed), it does demonstrate the minification problem. When minified, the resulting JavaScript is as follows:

var myApp;

function(n){
    n.module.directive("validator",[
        function(){
            return{
                link:function(t,i){
                    var r=[
                        {signal:"required",message:"Please enter a value",value:null},
                        {signal:"email",message:"Please enter a valid email address",value:null}
                    ];

                    $("input",i).on("blur",function(){
                        var i,
                        validator;

                        for(i in r)
                            if(validator=r[i],t.$parent.form[t.modelName].$error[validator.signal]){
                                i.removeClass("has-success");
                                t.errorMessage=n.Utility.formatString(validator.message,eval(validator.value));
                                break
                            }

                    })
                }
            }
        }
    ])
})(myApp||(myApp={}))

Note how minification has assigned the parameter names t and i to the link function, despite the fact that a loop variable i is used in the original code.

Needless to say, this breaks the code. In this case I can fix it by renaming my loop variable, but I am concerned that there may be other adverse consequences to JsMinify's minification that I am not aware of.

So, I have 3 questions related to this issue:

  • Am I right to assume that this is a minification bug and, if so, is there somewhere I should report it?
  • Is there any practical way of finding any other instances of this issue in my minified code?
  • Is it possible to replace the JavaScript minification engine used by System.Web.Optimization and, if so, what would be a good alternative?

Many thanks, in advance, for your ideas. Tim

Update: After some further investigation, I have discovered that it is actually WebGrease that performs minification on behalf of System.Web.Optimization and this issue appears to be the one that I am seeing. This seems to answer my first question, but I would still appreciate advice regarding alternative minifiers.


Solution

  • In the past, I have successfully used YUI Compressor for .Net, which is a .NET port from Java of YUI Compressor. The great thing about it is that it's based on Mozilla's Rhino JavaScript interpreter, meaning it actually understands the code, and not just runs regular expressions on it. As a result, it will fail your build if you have JavaScript syntax errors.