17

Using the latest version of MVC4 I can't minify javascript when it contains reserved words as key names!

See the error below with the valid javascript that should have been minified.

Does anyone know how to fix this short of rewriting the javascript to use [""] notation?

PS The code in question is a few thousand lines long, so it's not an option!

/* Minification failed. Returning unminified contents.
(3,9-15): run-time warning JS1010: Expected identifier: delete
(4,9-13): run-time warning JS1010: Expected identifier: case
(5,9-11): run-time warning JS1010: Expected identifier: if
(3,9-15): run-time error JS1137: 'delete' is a new reserved word and should not be used as an identifier: delete
(4,9-13): run-time error JS1137: 'case' is a new reserved word and should not be used as an identifier: case
(5,9-11): run-time error JS1137: 'if' is a new reserved word and should not be used as an identifier: if
 */
var context = {};

context.delete = {};
context.case = {};
context.if = {};

The question is without going with another option like node, cassette, combres, servicestack etc

How do we get MVC4 to play ball with reserved words.

I find it hard to believe that after 6 months plus that there is no support for this!

7
  • 3
    Just tried it my self and first thought. Hey it worked, since no obvious exception was displayed. But instead, the shit wasn't minified and a sneaky little comment was input in the JS. That's really ugly. Commented Nov 16, 2012 at 14:12
  • 1
    Haven't tested, but the Builder seems to be switchable per Bundle. Can't you assign one that switches values? Perhaps using the JsParser in WebGrease and using the Settings.AddRenamePair? Commented Nov 16, 2012 at 14:32
  • Hey James. A good question but why would Bundling support reserved words when the ECMASscript Standard advises against using them? developer.mozilla.org/en-US/docs/JavaScript/Reference/… Commented Nov 16, 2012 at 14:43
  • If you find away around it though I would be interested to know. Commented Nov 16, 2012 at 14:45
  • Actually i wonder if something could be added to the Minify/Bundles (Like we use for LESS etc) to maybe replace reserved words automatically into the """ notation....mmmmmnnn now thats something interesting to build. Commented Nov 16, 2012 at 14:53

2 Answers 2

9

Just tried this and it works. Sorry but the ugly code. It will replace your members named delete and the usages of them.

public class CustomBundle : ScriptBundle
{
    public CustomBundle(string virtualPath) : base(virtualPath)
    {
        this.Builder = new CustomBuilder();
    }
    public CustomBundle(string virtualPath, string cdnPath) : base(virtualPath, cdnPath) {}
}

public class CustomBuilder : IBundleBuilder {
    public string BuildBundleContent(Bundle bundle, BundleContext context, IEnumerable<FileInfo> files)
    {
        var content = new StringBuilder();
        foreach (var fileInfo in files)
        {
            var parser = new Microsoft.Ajax.Utilities.JSParser(Read(fileInfo));
            parser.Settings.AddRenamePair("delete", "fooDelete");
            content.Append(parser.Parse(parser.Settings).ToCode());
            content.Append(";");
        }

        return content.ToString();
    }

    private string Read(FileInfo file)
    {
        using(var r = file.OpenText())
        {
            return r.ReadToEnd();
        }
    }
}
Sign up to request clarification or add additional context in comments.

12 Comments

This is awesome Daniel, I'm definitely going to have a play with this.
Not much love in the code, but it will switch them, but only when minifiying. Blogged about it here: daniel.wertheim.se/2012/11/16/…
Would you agree if would be more efficient to put this sort of logic say in some MSBuild script?
I would say I think the optimization frameworks works nicely as it is. Used another a while back ago, that was triggered when building the code via call to some NodeJS script which could be used separately in our build process. I feel that that kind of solution is much more cumbersome to work with as a dev.
Thanks Daniel. After I have finished playing with Windows 8/C# XAML, I will have a look at your code and have a good play with it. I love questions like this that stop you from working and to think about a given problem.
|
4

Hope it's not too late. You can implement own minification transform and ignore these errors.

var bundle = new ScriptBundle("~/bundles/xxxbundle", null, new JsMinifyIgnoreReservedWordError()).
    Include("~/Scripts/xxx.js");

private class JsMinifyIgnoreReservedWordError : IBundleTransform
{
    private const string JsContentType = "text/javascript";

    public void Process(BundleContext context, BundleResponse response)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (response == null)
        {
            throw new ArgumentNullException("response");
        }
        if (!context.EnableInstrumentation)
        {
            Minifier minifier = new Minifier();

            string result = minifier.MinifyJavaScript(response.Content, new CodeSettings
            {
                EvalTreatment = EvalTreatment.MakeImmediateSafe,
                PreserveImportantComments = false,
                        IgnoreErrorList = "JS1137" // ignore 'is a new reserved word and should not be used as an identifier' error
                    });

            if (minifier.ErrorList.Count > 0)
            {
                GenerateErrorResponse(response, minifier.ErrorList);
            }
            else
            {
                response.Content = result;
            }
        }
        response.ContentType = JsContentType;
    }

    private static void GenerateErrorResponse(BundleResponse bundle, IEnumerable<object> errors)
    {
        StringBuilder stringBuilder = new StringBuilder();

        stringBuilder.Append("/* ");
        stringBuilder.Append("Minification failed. Returning unminified contents.").AppendLine();

        foreach (object error in errors)
        {
            stringBuilder.Append(error).AppendLine();
        }

        stringBuilder.Append(" */").AppendLine();
        stringBuilder.Append(bundle.Content);

        bundle.Content = stringBuilder.ToString();
    }
}

3 Comments

thanks @bigbangbyproduct i am able to accomplish this but i have to change ScriptBundle to Bundle as it has the correct constructor parameters.
also, to add more error numbers to the ignoreerrorlist, you can use comma-separated value.
Answers like this really show what Stack Overflow is all about. I'm not sure if I can find documentation on this technology anywhere else.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.