忽略MVC包中的文件

时间:2015-05-11 15:59:27

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

我们正在使用功能标记(在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);
}

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

5 个答案:

答案 0 :(得分:4)

我在使用表达式时也打过了忽略列表。我发现一个简单的工作是实现一个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);
}

答案 1 :(得分:2)

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

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

e.g。

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

答案 2 :(得分:1)

我在上面提出了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)
            );

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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