忽略 MVC 包中的文件
Ignoring files in MVC Bundles
我们正在使用功能标志(在 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);
}
通过上面的代码,忽略列表中的文件仍然被包含!我在这里做错了什么?
我认为捆绑代码只发生一次——在网站初始化期间。如果您在没有 restarting/republishing 网站的情况下切换 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>
}
尝试按如下方式定义忽略列表(使用通配符而不是相对路径):
bundles.IgnoreList.Ignore("*/App/Organization/SomeCtrl.js", OptimizationMode.Always);
bundles.IgnoreList.Ignore("*/App/Filters/SomeFilter.js", OptimizationMode.Always);
我在使用表达式时也曾与忽略列表作斗争。我发现一个简单的解决方法是实现一个 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);
}
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));
}
我对上面 Gent 的回答投了赞成票,因为它帮助我完成了我想要的。
但后来我对其进行了扩展并创建了一个通用的 IBundleOrderer
,它使用 lambda 来非常简单地排除您想要排除的任何项目。
请注意,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)
);
我们正在使用功能标志(在 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);
}
通过上面的代码,忽略列表中的文件仍然被包含!我在这里做错了什么?
我认为捆绑代码只发生一次——在网站初始化期间。如果您在没有 restarting/republishing 网站的情况下切换 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>
}
尝试按如下方式定义忽略列表(使用通配符而不是相对路径):
bundles.IgnoreList.Ignore("*/App/Organization/SomeCtrl.js", OptimizationMode.Always);
bundles.IgnoreList.Ignore("*/App/Filters/SomeFilter.js", OptimizationMode.Always);
我在使用表达式时也曾与忽略列表作斗争。我发现一个简单的解决方法是实现一个 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);
}
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));
}
我对上面 Gent 的回答投了赞成票,因为它帮助我完成了我想要的。
但后来我对其进行了扩展并创建了一个通用的 IBundleOrderer
,它使用 lambda 来非常简单地排除您想要排除的任何项目。
请注意,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)
);