Most websites use Javascript nowadays, and so often on those pages you'll find a lot of <script> and <link> tags:

<link rel="stylesheet" type="text/css" href="../Content/AppTheme.css">
<link rel="stylesheet" type="text/css" href="../Content/jQuery/Theme.css">
...
<script type="text/javascript" src="../Scripts/jquery-1.10.2.js"/>
<script type="text/javascript" src="../Scripts/jquery-ui-1.10.2.js"/>
<script type="text/javascript" src="../Scripts/modernizr-2.6.2.js"/>
<script type="text/javascript" src="../CustomScripts/ApplicationCore.js"/>
<script type="text/javascript" src="../CustomScripts/AddModules.js"/>
<script type="text/javascript" src="../CustomScripts/EditTask.js"/>

Each time a browser runs across one of these tags, it makes a separate HTTP request to grab the corresponding file. In the example above, the browser has to make 8 HTTP requests to grab all the scripts the page needs.

As of MVC4, we have a way to reduce the number of requests that the browser needs to make to get all of these resource files (and even reduce the size of the files themselves): Bundling and Minification.

Bundling

A standard ASP.NET MVC app has a file called BundleConfig.cs in the App_Start folder. By default, that file contains a class also called BundleConfig and looks something like this:

using System.Web;
using System.Web.Optimization;

namespace BundlingExample
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));

            bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
                      "~/Scripts/bootstrap.js",
                      "~/Scripts/respond.js"));

            bundles.Add(new StyleBundle("~/Content/css").Include(
                      "~/Content/bootstrap.css",
                      "~/Content/site.css"));

            BundleTable.EnableOptimizations = false;
        }
    }
}

Note that BundleTable.EnableOptimizations is false right now. This means that, when this application runs, the compiler will not bundle or minify our JS and CSS files.

The BundleConfig.cs file is creating Bundles by associating multiple files to routes. For example, the "~/bundles/bootstrap" route will correspond to both the bootstrap.js file and the respond.js file, and the browser will only need one HTTP request to retrieve both files. But how do we retrieve the files?

On a view, we use static classes Scripts and Styles:

@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/bootstrap")

This gives us nice, clean, easy-to-read syntax. Just define some bundles and render them on the views as necessary. However, there's a little more depth than that. For example, you may have noticed the use of tokens and wildcards in the scripts calls in BundleConfig. Adding a script to the bundle follows a couple conventions:

  • Using a token (e.g. {version}) will match all files with the token (see the jQuery example above).
  • Using a wildcard '*' will match everything at that position in the file name.

With these tokens and wildcards, we can handle production and debug scenarios easily (and they fit very nicely with MVC's general convention-over-configuration methodology).

EnableOptimizations and Debugging

The bundling system can be enabled/disabled in two methods: via the BundleTable.EnableOptimizations call above, or by setting debug="true" in the web.config.  If you set the property BundleTable.EnableOptimizations to true, that takes precedence over debug mode. With BundleTable.EnableOptimizations set to false (meaning bundling and minification is disabled), the output looks like this:

Shows the scripts each rendered separately

That allows us to see each file in the bundles separately, which is very useful for debugging. Let's modify the BundleConfig class to only disable optimizations in debugging:

public class BundleConfig
{
    ...
#if DEBUG
        BundleTable.EnableOptimizations = false;
#else
        BundleTable.EnableOptimizations = true;
#endif
    }
}

Now, if we run in debug mode, we'll see the separate files. So what happens in release mode?

Shows the scripts rendered as bundles

Each of those files are compiled into their bundles, reducing the number of HTTP requests the browser has to make from 5 down to 3.

Minification

But what does one of those files actually look like?

Shows a minified JavaScript file

That's pretty hard to read for a human, but optimized for a browser. MVC implements a process called minification on the bundled files. Minification removes all whitespace and renames variables to their shortest possible name, thereby removing all excess characters (and thereby excess file size) from the bundle. Because the file is smaller, it takes less time to download.

Summary

Bundling and Minification provide us a way to both reduce the number of requests needed to get JS and CSS resource files and reduce the size of the files themselves, thereby improving the responsiveness of our apps. They are nice little optimizations for our MVC apps that can improve performance and add responsiveness.

So go get out there and start bundling!

Happy Coding!