【问题标题】:Ignoring files in MVC Bundles忽略 MVC 包中的文件
【发布时间】:2015-05-11 15:59:26
【问题描述】:

我们正在使用功能标志(在 Web.Config 中设置)来切换某些尚未完成的功能在 UI 中的可见性。我还希望我的 MVC 包不包含相关的 JS 文件,因为它们只是在未启用该功能时客户端必须下载的无用文件。

到目前为止,我已经找到了 IgnoreList.Ignore,但我似乎无法让它工作。这基本上就是我正在做的事情:

public static void RegisterBundles(BundleCollection bundles)
{
    if (!appConfiguration.FeatureXEnabled)
    {
        //Skip these files if the Feature X is not enabled!
        //When this flag is removed, these lines can be deleted and the files will be included like normal
        bundles.IgnoreList.Ignore("~/App/Organization/SomeCtrl.js", OptimizationMode.Always);
        bundles.IgnoreList.Ignore("~/App/Filters/SomeFilter.js", OptimizationMode.Always);
    }

    var globalBundle = new ScriptBundle("~/bundles/app-global").Include(
        "~/App/RootCtrl.js",
        "~/App/Directives/*.js",
        "~/App/Services/*.js",
        "~/App/Application.js"
    );
    bundles.Add(globalBundle);

    var appOrgBundle = new ScriptBundle("~/bundles/app-org");
    appOrgBundle.Include(
        "~/App/Filters/*.js",
        "~/App/Organization/*.js"
    );

    bundles.Add(appOrgBundle);
}

使用上面的代码,忽略列表中的文件仍然被包含在内!我在这里做错了什么?

【问题讨论】:

    标签: c# asp.net-mvc bundling-and-minification


    【解决方案1】:

    我在使用表达式时也与忽略列表作斗争。我发现一个简单的解决方法是实现一个IBundleOrderer,它将排除我不想要的文件,并对文件的包含方式应用一些排序。虽然这并不是它真正的预期用途,但我发现它填补了空白。

    IBundleOrderer 可以访问完整的文件列表(表达式扩展为匹配的文件)。

    public class ApplicationOrderer : IBundleOrderer {
        public IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
        {
            if (!AppSettings.FeatureFlag_ServiceIntegrationsEnabled)
            {
                //Skip these files if the Service Integrations Feature is not enabled!
                //When this flag is removed, these lines can be deleted and the files will be included like normal
                var serviceIntegrationPathsToIgnore = new[]
                {
                    "/App/ServiceIntegrations/IntegrationSettingsModel.js",
                    "/App/ServiceIntegrations/IntegrationSettingsService.js",
                    "/App/ServiceIntegrations/ServiceIntegrationsCtrl.js"
                };
                files = files.Where(x => !serviceIntegrationPathsToIgnore.Contains(x.VirtualFile.VirtualPath));
            }
    
            return files;
        }
    }
    

    示例用法:

    public static void RegisterBundles(BundleCollection bundles)
    {
            var appBundle = new ScriptBundle("~/bundles/app")
                .IncludeDirectory("~/App/", "*.js", true)
            appBundle.Orderer = new ApplicationOrderer();
            bundles.Add(appBundle);
    }
    

    【讨论】:

      【解决方案2】:

      我认为捆绑代码只发生一次 - 在网站初始化期间。如果您在不重新启动/重新发布网站的情况下切换 appConfiguration.FeatureXEnabled 标志,那么您的更改将被忽略。

      一种解决方案是创建 2 个单独的包,然后使用 Razor 在 HTML 中显示正确的包引用。

      例如

      @{if (appConfiguration.FeatureXEnabled){
          <script type="text/javascript" src="~/bundles/bundle-large.js"></script>
      }else{
          <script type="text/javascript" src="~/bundles/bundle-small.js"></script>
      }
      

      【讨论】:

      • 我认为你可能是对的。标志值在web.config 文件中,因此不会动态切换。如何在本地“重新启动/重新发布”?我已经尝试停止 IIS 并重新启动 Visual Studio。不用找了。如果不需要,我宁愿不必制作不同的捆绑包。
      • 我原以为停止 IIS 并重新启动 VS 就足够了。尝试删除网站二进制文件。或者问题可能出在其他地方?你确定你选择了正确的配置值吗?
      • 是的,我什至在调试模式下单步执行了代码,以确保这些行被命中。它们是,但这些脚本仍然包含在内。
      • 您总是可以编写自己的包。 (看起来很简单。)至少你可以控制忽略列表的处理方式。 stevescodingblog.co.uk/…
      【解决方案3】:

      我赞成 Gent 在上面的回答,因为它帮助我完成了我想要的。

      但后来我对其进行了扩展并创建了一个通用的IBundleOrderer,它使用 lambdas 非常简单地排除您想要排除的任何项目。

      请注意,excludes 参数是一个params 列表,因此您不受单一排除模式的限制。这不做任何排序,但可以很容易地添加另一个参数。

      public class ExcludeItemsOrderer : IBundleOrderer
      {
          private Func<BundleFile, bool>[] _excludes;
      
          public ExcludeItemsOrderer(params Func<BundleFile, bool>[] excludes)
          {
              _excludes = excludes;
          }
      
          public IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
          {
              if(_excludes == null || _excludes.Length == 0)
              {
                  return files;
              }
      
              foreach(var exclude in _excludes)
              {
                  var exclusions = files.Where(exclude);
                  files = files.Except(exclusions);
              }
      
              return files;
          }
      }
      

      然后我创建了一个扩展方法来简化使用它:

      public static class BundleExtensions
      {
          public static Bundle AsIsOrderExcluding(this Bundle bundle, params Func<BundleFile, bool>[] excludes)
          {
              bundle.Orderer = new ExcludeItemsOrderer(excludes);
              return bundle;
          }
      }
      

      这样它就可以在您创建捆绑包时轻松应用,如下所示:

      bundles.Add(
                  new ScriptBundle("~/Bundles/App/js")
                      .IncludeDirectory("~/App", "*.js", true)
                      .AsIsOrderExcluding(bf => bf.VirtualFile.VirtualPath.IndexOf("/skip_me/") >= 0)
                  );
      

      【讨论】:

      • 不错的通用 impl 允许我减少样板文件,因为我在多个 Web 项目中使用它。谢谢!
      【解决方案4】:

      尝试如下定义忽略列表(使用通配符而不是相对路径):

         bundles.IgnoreList.Ignore("*/App/Organization/SomeCtrl.js", OptimizationMode.Always);
         bundles.IgnoreList.Ignore("*/App/Filters/SomeFilter.js", OptimizationMode.Always);
      

      【讨论】:

        【解决方案5】:

        Bundles.IgnoreList.Ignore(pattern) 不能这样工作。它仅将文件的 Name 部分(即不是完整(虚拟)路径)与要返回的任何捆绑包中的 pattern 进行比较。 例如,您可以忽略名称以 old_style 前缀开头的文件。此过滤将应用于任何文件夹下的文件。

        public IEnumerable<BundleFile> FilterIgnoredFiles(BundleContext context, IEnumerable<BundleFile> files) { return files.Where(f => !ShouldIgnore(context, f.VirtualFile.Name)); }

        见: https://aspnetoptimization.codeplex.com/SourceControl/latest#src/System.Web.Optimization/IgnoreList.cs

        【讨论】:

          猜你喜欢
          • 2016-09-02
          • 1970-01-01
          • 2013-05-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-31
          • 1970-01-01
          相关资源
          最近更新 更多