ASP.NET MVC 4 Bundling and Minification

ASP.NET MVC 4 Bundling and Minification

ASP.NET MVC 4 provides bundling and minification of CSS and JavaScript, which reduces the number of HTTP Requests and payload size resulting in faster and better performing ASP.NET MVC Websites. There are a number of ways you can reduce and combine the size of CSS and JavaScript using the new feature, and in this ASP.NET MVC 4 Tutorial I want to show how you can create custom bundles where you specify the name and order of CSS and JavaScript Files. In this case, I specify the CSS and JavaScript that is part of Twitter Bootstrap. Don't forget to also check out my previous ASP.NET MVC 4 Post - ASP.NET MVC 4 and Entity Framework Database Migrations.

ASP.NET MVC 4 BundleTable and Bundles

If you create an empty ASP.NET MVC 4 Project, you will notice a couple of changes in the _Layout.cshtml and Global.asax.cs files. The _Layout.cshtml file will include Razor Code referencing System.Web.Optimization and BundleTable.Bundles in the CSS and JavaScript References in the head of the file:

<link href="@System.Web.Optimization.BundleTable.
    Bundles.ResolveBundleUrl("~/Content/css")"
    rel="stylesheet"
    type="text/css" />
<link href="@System.Web.Optimization.BundleTable.
    Bundles.ResolveBundleUrl("~/Content/themes/base/css")"
    rel="stylesheet"
    type="text/css" />
<script src="@System.Web.Optimization.BundleTable.
    Bundles.ResolveBundleUrl("~/Scripts/js")"></script>

These references are for ASP.NET MVC 4 Beta and will be shortened in the production version of ASP.NET MVC 4 as a simple HTML Helper. If you look at the actual source code in the browser, you will see these get rendered as:

<link href="/Content/css?v=ji3nO1pdg6VLv3CVUWntxgZNf1z"
rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/css?v=UM624qf1uFt8dYti"
rel="stylesheet" type="text/css" />
<script src="/Scripts/js?v=4h5lPNUsLiFoa0vqrItjS2Jp"></script>

The CSS and JavaScript files in the empty ASP.NET MVC 4 project end up being minified and compressed and a cache busting querystring parameter (v) is a hash of the current files being served and will change as the CSS and JS changes. The result is less HTTP Requests in your ASP.NET MVC 4 web application and a reduction in the size of the CSS and JavaScript sent by the IIS Web Server.

In Global.asax.cs you will notice a reference to the new BundleTable in Application Startup:

BundleTable.Bundles.RegisterTemplateBundles();

This is a method in System.Web.Optimization that registers two bundles that combine and minify the default CSS and JavaScript that ships with the "empty" ASP.NET MVC 4 Project.

Twitter Bootstrap ASP.NET MVC 4 Bundles

I finished creating a Twitter Bootstrap Orchard Theme and thought I would create Twitter Bootstrap Bundles to test the new bunding and minification in ASP.NET MVC 4. I went ahead and created an extension method for BundleCollection and created the following 2 bundles that specify the list of CSS and JavaScript Files I wanted in these two bundles.

public static void EnableBootstrapBundle(this BundleCollection bundles) {
      var bootstrapCss = new Bundle("~/bootstrap/css", new CssMinify());
      bootstrapCss.AddFile("~/css/bootstrap.css");
      bootstrapCss.AddFile("~/css/bootstrap-responsive.css");
      bootstrapCss.AddFile("~/css/application.css");
      bootstrapCss.AddFile("~/css/prettify.css");

      bundles.Add(bootstrapCss);

      var bootstrapJs = new Bundle("~/bootstrap/js", new JsMinify());
      bootstrapJs.AddFile("~/js/jquery-1.7.1.js");
      bootstrapJs.AddFile("~/js/bootstrap.js");
      bootstrapJs.AddFile("~/js/prettify.js");

      bundles.Add(bootstrapJs);
}

By default, a new Bundle in ASP.NET MVC 4 will only combine CSS or JavaScript Files unless you specify an IBundleTransform. In this case we specify CssMinify and JsMinify, which compress and optimize the CSS and JavaScript. You could, for example, use these bundles to combine and compress CoffeeScript, too, which is the subject of another post.

In the Global.asax.cs file I add the Twitter Bootstrap Bundles to the ASP.NET MVC 4 BundleTable with one simple call:

BundleTable.Bundles.EnableBootstrapBundle();

In the _Layout.cshtml I reference these new CSS and JavaScript Bundles similar to the way they are done in the Empty ASP.NET MVC 4 Project.

<link href="@System.Web.Optimization.BundleTable.
      Bundles.ResolveBundleUrl("~/bootstrap/css")" rel="stylesheet">
<script src="@System.Web.Optimization.BundleTable.
      Bundles.ResolveBundleUrl("~/bootstrap/js")"></script>

Again, in the production version of ASP.NET MVC 4 this is supposed to be a simple HTML Helper as opposed to the long reference to System.Web.Optimization.

The end result is that all the Twitter Bootstrap CSS and JavaScript files are now combined and compressed into single files with the cache buster querystring parameter that will change as changes are made to the files combined and compressed via ASP.NET MVC 4.

<link href="/bootstrap/css?v=uBlJsuIAGAF93nUTTez8"
      rel="stylesheet">
<script src="/bootstrap/js?v=O6HaHC8QqtB"></script>

No extra build tasks. No manual work to combine and compress the CSS and JavaScript. All of this is built into ASP.NET MVC 4!

CDN Support

I haven't had a chance to dive into all the aspects of ASP.NET MVC 4's new bundling and minification, but there doesn't appear to be any support for CDN's. In my Twitter Bootstrap example, ideally I would return jQuery from the Google or Microsoft CDN. I cannot find a setting to specify a CDN for certain JavaScript files as well as a local alternative if the CDN is unavailable. I guess I could hardcode it in the _Layout.cshtml file separately, but I would prefer to keep it all nice and tidy in the bundle.

Debug Mode Support

When debugging your ASP.NET MVC 4 Web Application you would rather the CSS and JavaScript not be bundled and minified for testing. Unfortunately, I cannot find a setting in the ASP.NET MVC 4 bundling and minification that detects debugging enabled and skips the bundling and minification. It seems both in production and debugging scenarios the CSS and JavaScript is always bundled and/or minified with no way to change that behavior when testing. This needs to be implemented before ASP.NET MVC 4 is released as well as the CDN support.

Orchard CMS for Inspiration

As an aside, one of the many things I like about Orchard CMS, which is built on ASP.NET MVC, is the way it handles CSS and JavaScript assets. Although it doesn't minify and combine these resources out-of-the-box, Orchard has a neat way of managing what CSS and JavaScript should be included in the rendering of the page. It has various helpers like Script.Include("application.js"), Script.Require("jQuery"), Style.Include("site.css"), and Style.Require("Admin") which manage what scripts and stylesheets are required or optional if missing when the page is rendered.

In addition to specifying the assets, you can also specify specific asset versions and dependencies on other assets and Orchard will handle the proper ordering of these stylesheets and scripts in the page. You can also specify production, debugging, and CDN versions of these assets. And, last, in the case of JavaScript, you can also specify if it should be rendered at the head or foot of the page.

Ideally I would love it if ASP.NET MVC 4 took some cues from Orchard CMS and added some of these features.

Conclusion

The new bundling and minification in ASP.NET MVC 4 will help increase the performance of your ASP.NET MVC 4 Websites by reducing the number and size of HTTP Requests to the server. There are some glaring issues in the beta release so hopefully they will implement them before production release. This is just one ASP.NET MVC 4 Feature. Check out other ASP.NET MVC 4 Tutorials.