Let's suppose I have these two script bundles configured:
bundles.Add(new ScriptBundle("~/Scripts/Bootstrap").Include(
"~/Content/Scripts/jQuery/jquery-2.1.1.js",
"~/Content/Scripts/Bootstrap/bootstrap.js"));
bundles.Add(new ScriptBundle("~/Scripts/jQuery").Include(
"~/Content/Scripts/jQuery/jquery-2.1.1.js"));
As you can see, ~/Scripts/Boostrap
uses a jQuery JavaScript file and a Bootstrap one. This is because the Bootstrap one requires jQuery to work.
On the other hand, ~/Scripts/jQuery
is composed of only the jQuery file.
I want to have two bundles in case a view only needs jQuery and not Bootstrap.
However, I am replicating code here, I am defining the jQuery JavaScript file path twice.
Is there a way to tell the ~/Scripts/Boostrap
bundle to use or "inject" another bundle?
Something like this:
bundles.Add(new ScriptBundle("~/Scripts/Bootstrap").UseBundle("~/Scripts/jQuery").Include(
"~/Content/Scripts/Bootstrap/bootstrap.js"));
Make a script bundle include another script bundle
Not directly using the Bundling class.
Let say in your scenario that the business decides to only send a single bundle to the client for every request. You've decided to bundle all the scripts needed for each controller (in this magical world). You might start off with something like this:
bundles.Add(new ScriptBundle("~/Scripts/Home")
.Include("~/Content/Scripts/jQuery/jquery-2.1.1.js",
"~/Content/Scripts/Bootstrap/bootstrap.js"
"~/Content/Scripts/Home.js"));
bundles.Add(new ScriptBundle("~/Scripts/Account")
.Include("~/Content/Scripts/jQuery/jquery-2.1.1.js",
"~/Content/Scripts/Bootstrap/bootstrap.js"
"~/Content/Scripts/Account.js"));
Then realizing that .Include(string[]) simply takes an array of string, you could DRY your code into something like:
var commonScripts = new List<string>()
{
"~/Content/Scripts/jQuery/jquery-2.1.1.js",
"~/Content/Scripts/Bootstrap/bootstrap.js"
};
var homeScripts = new List<string>()
{
"~/Content/Scripts/Home.js"
};
bundles.Add(new ScriptBundle("~/bundles/home/")
.Include(commonScripts.Concat(homeScripts).ToArray()));
var accountScripts = new List<string>()
{
"~/Content/Scripts/Account.js"
};
bundles.Add(new ScriptBundle("~/bundles/account/")
.Include(commonScripts.Concat(accountScripts).ToArray()));
I don't recommend the business reasons behind this solution, but I think the logic that solves it could be used similarly to solve your problem.
If you think you're going to possibly have duplicates you could also:
.Include(commonScripts.Concat(accountScripts)
.Distinct()
.ToArray()));
Personally I wouldn't include jQuery or BootStrap in bundles, as they are available from many CDNs online for free which; A means I use less of my bandwidth, and B the client may have already downloaded the scripts I need (The reasons CDNs exist for common scripts/styles anyway).
You could also consider creating a ComposableBundle
wrapper class that allows you to compose bundles with the .UseBundle(someBundle)
syntax.
For example the following class and extensions methods:
public class ComposableBundle<T> where T : Bundle
{
private T _bundle;
private List<string> _virtualPaths = new List<string>();
public ComposableBundle(T bundle)
{
_bundle = bundle;
}
public string[] VirtualPaths
{
get { return _virtualPaths.ToArray(); }
}
public T Bundle
{
get { return _bundle; }
}
public ComposableBundle<T> Include(params string[] virtualPaths)
{
_virtualPaths.AddRange(virtualPaths);
_bundle.Include(virtualPaths);
return this;
}
public ComposableBundle<T> UseBundle(ComposableBundle<T> bundle)
{
_bundle.Include(bundle.VirtualPaths.ToArray());
return this;
}
}
public static class BundleExtensions
{
public static ComposableBundle<T> AsComposable<T>(this T bundle) where T : Bundle
{
return new ComposableBundle<T>(bundle);
}
public static ComposableBundle<T> Add<T>(this BundleCollection bundles, ComposableBundle<T> bundle) where T: Bundle
{
bundles.Add(bundle.Bundle);
return bundle;
}
}
Would allow you to configure your bundles like this:
var jQueryBundle = bundles.Add(new ScriptBundle("~/bundles/jquery").AsComposable()
.Include("~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui").AsComposable()
.UseBundle(jQueryBundle)
.Include("~/Scripts/jquery-ui-{version}.js"));