MVC.. 4? Already?! Bundling, Minification, what??

If you’ve been following all the cool new stuff coming in MVC 4, you’ve probably heard of the new Bundling & Minification features. They are seperate, but I like to think of them as parallel concerns. And apparently, Microsoft does too!

<link href="content/reset.css" rel="Stylesheet" />
<link href="content/styleguide.css" rel="Stylesheet" />
<link href="content/style.css" rel="Stylesheet" />
<link href="content/itemlist.css" rel="Stylesheet" />
<link href="content/css.css" rel="Stylesheet" />
<script src="script/widget.js" type="text/javascript"></script>
<script src="script/watermark.js" type="text/javascript"></script>
<script src="script/slideshow.js" type="text/javascript"></script>
<script src="script/dropdown.js" type="text/javascript"></script>

Look familiar? This is what many sites look like, and it actually presents us two opportunities for optimization.

To minify, or not and how to minify

The practice of shrinking or ‘minifying’ script and stylesheet files has become pretty common lately, and there are many ways of doing so. Most methods involve either running a script during deployment that shrinks your existing JS files, or using one of many minification libraries to minify your files on the fly.

Sounds like a pain, but it doesn’t need to be. Not anymore.

Why eggs aren’t sold separately

What if eggs were sold separately; that wouldn’t be much fun. Not that eggs being sold in dozens is much fun either, but it would really be no fun at all to buy them individually. They’d always be rolling around in your cart and if you put anything on them they’d break and make a mess.

Unbundled scripts and stylesheets aren’t quite as messy as a couple dozen eggs rolling around in your cart as you shop, but they do slow down the browsing experience for anyone visiting your website. As soon as their browser hits your site it starts parsing HTML, and figuring out what else it needs to download before it can begin rendering it. Between stylesheets, scripts, and images, there can be a lot of files required. And for each of those files the browser needs to open a connection and request that file.

“Yeah, ok, 30 simultaneous connections.. who cares?” you may be asking yourself. Well most modern browsers are limited to 6 or 8 simultaneous connections per domain, so if it has to get a few big css and js files, the browser will have to wait for those to come down the pipe before requesting your images and whatever else is on your page. And if you’re using Webforms it’s doing all of that while chugging through that big viewstate download too, ugh!!

“But I use subdomain trickery to make your browser think that it’s downloading each script & image from a different server!” Well alright, you win. For the rest of us that want a simple solution though, here it is:

<link href="content/css" rel="Stylesheet" />
<script src="script/js" type="text/javascript"></script>

“Where did my files go?” Well they probably saved to your my doc- er wait, sorry. In all seriousness though, your files are still there. ASP.NET just took all of your CSS & script files and created one CSS and one JS file, all bundled up and minified like scrambled eggs and sent it to your browser. What you are actually doing is telling the framework that you want to take all “content/*.css” files and combine them into one (minified) file, and then the same for “script/*.js”.

There are also some built-in helpers in the namespace that allow you to do the same thing with a bonus feature of helping you with caching:

<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/content/css")" rel="Stylesheet" />
<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/script/js")" type="text/javascript"></script>

What this does is actually make a hash of the file to be served and appends that hash to the url of the file that the browser requests. This could end up looking like this:

<link href="/Content/css?v=2nL7Ibd5cnOVWsLuIeyRaOhIF5ZHdQKX2-9LZ2jBpuVyS7kMr6iNEf9OqoHSqsfI" rel="Stylesheet" type="text/css" />
<script src="/script/js?v=VR7ocQF24ZSnoI7UDcmoFdsWKYA_9SNYPo4BPWsiNwD4uxScIysQcdzNgMgdioh8 type="text/javascript"></script>

And the beautiful thing is that any time the file changes, the hash will change too. Now you can keep those files cached on the client or anywhere else almost indefinitely and the client will never be stuck with a stale file.

Custom Bundles (I micro-manage my eggs)

You can also create custom bundles and force files to be bundled in order by dropping code such as this into the Application_Start() method inside your global.asax file.

Bundle mobileBundle = new Bundle("~/android", new JsMinify());
mobileBundle.AddFile("~/scripts/mobile/droid.js");
mobileBundle.AddFile("~/scripts/mobile/droid-dropdown.js");
mobileBundle.AddFile("~/scripts/mobile/droid-spin.js");
BundleTable.Bundles.Add(mobileBundle);

It will produce very similar results to the convention-based bundling but with more control for those who need it.

How to get started

At the time of this writing, you can get started with this feature right in Visual Studio 2010 by downloading the MVC 4 beta. In this case you will need to reference the System.Web.Optimization assembly (referenced by default on all MVC 4 projects). I haven’t tested it but I don’t see why you couldn’t do this in an ASP.NET project also.

The other option is to download the full-blown Visual Studio 11 beta. In this case you will still be using the System.Web.Optimization namespace, but this time it is included in v4.5 of System.Web.dll.

If you have any questions let me know, I’ve got some eggs to clean up.

Leave a Reply

Your email address will not be published. Required fields are marked *