We are using feature flags (set in Web.Config) to toggle the visibility in the UI of certain features that aren't yet complete. I'd also like my MVC bundles to NOT include the related JS files since they would just be useless files the client would have to download when the feature isn't enabled.
So far I've found IgnoreList.Ignore
but I can't seem to get it to work. This is basically what I'm doing:
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);
}
With the above code, the files in the ignore list are still being included! What am I doing wrong here?
I have fought the ignore list when using expressions as well. A simple work around I have found is to implement an IBundleOrderer
that will exclude the files I do not want, and apply some ordering to how the files get included. Although this is not really its intended use, I find it fills the gap.
The IBundleOrderer
gets access to the full list of files (expression expanded to what files it matched).
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;
}
}
Example Usage:
public static void RegisterBundles(BundleCollection bundles)
{
var appBundle = new ScriptBundle("~/bundles/app")
.IncludeDirectory("~/App/", "*.js", true)
appBundle.Orderer = new ApplicationOrderer();
bundles.Add(appBundle);
}
I think that the bundling code only happens once - during the initialisation of the website. If you are switching the appConfiguration.FeatureXEnabled
flag without restarting/republishing the website then your change will be ignored.
One solution would be to create 2 separate bundles and then use Razor to display the correct bundle reference in your 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>
}
I upvoted Gent's answer above because it helped me accomplish what I wanted.
But then I expanded upon it and created a generic IBundleOrderer
that uses lambdas to exclude whatever items you want to exclude very simply.
Note the excludes parameter is a params
list so you are not limited to a single exclusion pattern. This doesn't do any ordering, but it could be easily added with another parameter.
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;
}
}
And then I created an extension method to simplify using it:
public static class BundleExtensions
{
public static Bundle AsIsOrderExcluding(this Bundle bundle, params Func<BundleFile, bool>[] excludes)
{
bundle.Orderer = new ExcludeItemsOrderer(excludes);
return bundle;
}
}
So that it can be easily applied as you create your bundles, like this:
bundles.Add(
new ScriptBundle("~/Bundles/App/js")
.IncludeDirectory("~/App", "*.js", true)
.AsIsOrderExcluding(bf => bf.VirtualFile.VirtualPath.IndexOf("/skip_me/") >= 0)
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With