【问题标题】:Automatically detect minification failures in ASP.NET MVC bundling自动检测 ASP.NET MVC 捆绑中的缩小失败
【发布时间】:2019-06-28 07:21:44
【问题描述】:

我不时注意到由 ASP.NET MVC 生成的 CSS 包顶部出现以下错误消息:

/* Minification failed. Returning unminified contents.
(7933,26): run-time error CSS1019: Unexpected token, found ':'
(7933,26): run-time error CSS1042: Expected function, found ':'
(7933,26): run-time error CSS1062: Expected semicolon or closing curly-brace, found ':'
(7934,30): run-time error CSS1019: Unexpected token, found ':'
(7934,30): run-time error CSS1042: Expected function, found ':'
(7934,30): run-time error CSS1062: Expected semicolon or closing curly-brace, found ':'
 */

这些错误总是默默地通过构建、部署和单元测试,并且很难注意到。有什么解决方案可以自动捕获它们吗?很难从单元测试中得到它,因为没有内容文件夹被复制到单元测试项目中。最好这应该使构建或至少单元测试失败。

【问题讨论】:

    标签: asp.net unit-testing model-view-controller deployment bundling-and-minification


    【解决方案1】:

    在一个不包含测试的项目中,使用James Close answer,我能够在加载系统时显示缩小失败的警报,虽然它没有导致编译失败,但我们设法捕获了失败在开发环境中:

    public static IHtmlString Render(this BundleCollection bundles, string bundleVirtualPath) {
        Bundle bundle = bundles.GetBundleFor(bundleVirtualPath);
        List<IHtmlString> renderTags = new List<IHtmlString>();
    
        ... omitted for simplification
    
        List<string> errors;
        if (!bundle.IsValid(out errors)) {
            renderTags.Add(new HtmlString($"<script type='text/javascript'>alert('{HttpUtility.JavaScriptStringEncode(string.Join(Environment.NewLine, errors))}');</script>"));
        }
    
        return MvcHtmlString.Create(string.Join(Environment.NewLine, renderTags));
    }
    
    
    private static bool IsValid(this Bundle bundle, out List<string> errors) {
        errors = new List<string>();
    
        // Get items in included order
        BundleContext bundleContext = new BundleContext(new HttpContextWrapper(HttpContext.Current), new BundleCollection(), Guid.NewGuid().ToString());
        IEnumerable<BundleFile> bundleFiles = bundle.EnumerateFiles(bundleContext);
        bool isStyleBundle = (bundle is StyleBundle);
    
        foreach (BundleFile bundleFile in bundleFiles) {
            string physicalPath = HttpContext.Current.Server.MapPath(bundleFile.IncludedVirtualPath),
                    fileContent = File.ReadAllText(physicalPath);
    
            // Create minifier used by webgrease System.Web.Optimization
            var minifier = new Microsoft.Ajax.Utilities.Minifier();
            if (isStyleBundle) {
                minifier.MinifyStyleSheet(fileContent);
            } else {
                minifier.MinifyJavaScript(fileContent);
            }
    
            // Verify error in minification
            if (minifier.Errors.Any()) {
                errors.Add($"Minification failed for {bundleFile.IncludedVirtualPath}, errors:{Environment.NewLine}{string.Join(Environment.NewLine, minifier.Errors)}");
            }
        }
    
        return errors.Any();
    }
    

    希望上面的代码以后可以帮助到别人。

    【讨论】:

    • MVC/ASP菜鸟问题:Render函数应该放在哪里?
    【解决方案2】:

    我有同样的问题,想对缩小进行单元测试,在尝试模拟 BundleContext 的一些错误开始后,我选择直接测试 webgrease Microsoft.Ajax.Utilities.Minifier 提供的缩小,小问题是BundleItem是 System.Web.Optimization 内部的,所以我必须进行反思:

      //arrange
      BundleCollection bundles = new BundleCollection();
    
      // my static bundler config in mvc
      BundleConfig.RegisterBundles(bundles); 
    
      // act and assert
      Assert.Multiple(() =>
      {
        foreach (var bundle in bundles)
        {
          // CAUTION: Reflection to private member!
          var items = typeof(Bundle).GetProperty("Items", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(bundle) as IEnumerable<Object>;
          foreach (Object item in items)
          {
            var minifier = new Minifier();
            var type = item.GetType();
            var path = type.GetProperty("VirtualPath")?.GetValue(item) as String;
    
            // todo: handle "BundleDirectoryItem" too ...
            if (type.Name == "BundleItem")
            {
              // todo: transform your virtual path to a physical path to the file at design time
              var file = File.ReadAllText(path);
              String min;
              if (path.EndsWith("css"))
              {
                min = minifier.MinifyStyleSheet(file);
              }
              else
              {
                min = minifier.MinifyJavaScript(file);
              }
              Assert.IsNotNull(min, $"Failed to get minified output for '{path}'");
              Assert.Zero(minifier.Errors.Count, $"Minification failed for '{path}', errors:\r\n{String.Join("\r\n", minifier.Errors)}");
            }
          }
        }
      });
    

    【讨论】:

    • 像魅力一样工作,谢谢! JFYI:我必须在单元测试 csproj 文件中手动链接我的内容:&lt;ItemGroup&gt; &lt;Content Include="..\MyWebSite\Content\**\*.*"&gt; &lt;Link&gt;Content\%(RecursiveDir)%(FileName)%(Extension)&lt;/Link&gt; &lt;CopyToOutputDirectory&gt;PreserveNewest&lt;/CopyToOutputDirectory&gt; &lt;/Content&gt; &lt;/ItemGroup&gt;
    猜你喜欢
    • 2013-10-02
    • 2017-01-17
    • 1970-01-01
    • 2012-12-25
    • 2013-02-21
    • 2014-04-16
    • 2014-03-19
    • 2013-05-16
    • 2017-12-12
    相关资源
    最近更新 更多