MVC4捆绑最小化无法处理JavaScript保留字

16

使用最新版本的MVC4时,当JavaScript代码中包含保留字作为键名时,我无法对其进行缩小。

请查看下面的错误,其中包含了应该被缩小的有效JavaScript代码。

有人知道除了重写JavaScript并使用[""]符号之外,如何修复这个问题吗?

顺便说一句,相关代码有几千行,所以这不是一个选项!

/* 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 = {};

问题是不使用其他选项,如node、cassette、combres、servicestack等,如何使MVC4能够与保留字兼容。

我觉得很难相信在6个多月之后仍然没有对此提供支持!


3
我自己尝试了一下,第一个想法是:嘿,它起作用了,因为没有显示任何明显的异常。但是,相反,这个东西没有被压缩,并且在JS中输入了一个隐秘的小注释。这真的很丑陋。 - Daniel
1
尚未测试,但生成器似乎可以在每个 Bundle 中进行切换。您不能分配一个切换值的生成器吗?也许可以使用 WebGrease 中的 JsParser 并使用 Settings.AddRenamePair? - Daniel
嗨,詹姆斯。这是一个好问题,但为什么Bundling会支持保留字,而ECMASscript标准建议不要使用它们呢?https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Lexical_grammar#Reserved_keywords_as_of_ECMAScript_2015 - garfbradaz
其实我在想能否在Minify/Bundles中添加一些东西(就像我们用于LESS等)自动将保留字替换为"""符号...嗯,这是一个有趣的构建点。 - garfbradaz
以下是Daniel完成的(干得好,Daniel!):P - garfbradaz
显示剩余2条评论
2个回答

9

我刚尝试了这个方法,它可以运行。不好意思,代码有点丑陋。它将替换您命名为delete的成员及其用法。

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();
        }
    }
}

1
代码中没有太多的爱,但是它会将它们切换,但只有在最小化时才会这样做。在这里发表了博客:http://daniel.wertheim.se/2012/11/16/customizing-the-minification-of-javascript-in-asp-net-mvc4-allowing-reserved-words/ - Daniel
你认为将这种逻辑放在某个 MSBuild 脚本中会更有效吗? - garfbradaz
1
我认为优化框架目前的工作表现不错。之前使用过另一个框架,需要通过调用一些 NodeJS 脚本来构建代码,这种解决方案对于开发人员来说更加繁琐。 - Daniel
谢谢Daniel。在我完成了Windows 8/C# XAML的玩耍之后,我会看看你的代码并好好地玩一下。我喜欢这样的问题,它们能让你停下手头的工作,思考一个给定的问题。 - garfbradaz
@garfbradaz 在标识符名称中允许使用保留字,有关“保留字用法”的段落请参见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Reserved_Words。 - James Kyburz
显示剩余7条评论

2
希望还不算太晚。您可以实现自己的缩小转换并忽略这些错误。
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();
    }
}

1
感谢 @bigbangbyproduct 的帮助,我已经完成了这个任务,但是我不得不将 ScriptBundle 更改为 Bundle,因为它具有正确的构造函数参数。 - Aizzat Suhardi
1
另外,要将更多的错误号添加到ignoreerrorlist中,您可以使用逗号分隔的值。 - Aizzat Suhardi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接