Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a script bundle include another script bundle

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"));
like image 732
Matias Cicero Avatar asked Dec 18 '14 18:12

Matias Cicero


People also ask

What is difference between bundling and minification?

Both bundling and minification are the two separate techniques to reduce the load time. The bundling reduces the number of requests to the Server, while the minification reduces the size of the requested assets.

How do you override the bundling setting of web config?

To enable bundling and minification, set the debug value to "false". You can override the Web. config setting with the EnableOptimizations property on the BundleTable class. The following code enables bundling and minification and overrides any setting in the Web.

What is the benefit of bundling .js scripts into one file?

Bundling reduces the number of individual HTTP requests to server by combining multiple CSS files and Javascript files into single CSS file and javascript file. Minification reduces the file download size of CSS and javascript files by removing whitespace, comments and other unnecessary characters.


2 Answers

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).

like image 107
Erik Philips Avatar answered Oct 18 '22 01:10

Erik Philips


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"));
like image 11
Daniel J.G. Avatar answered Oct 18 '22 02:10

Daniel J.G.