Minify and Bundling Web Resources
The difficulty is in setting up your development environment so that this is done automatically. There seems to be loads of different ways to do this, varying from HttpHandlers to MsBuild tasks, with so many different ways to achieve the same (and quite simple task) most developers are stung with analysis paralysis.
MVC, make the decision for me
To make the decision easier MVC4 will ship with the library to fulfill your bundling and minifying needs. The namespace
System.Web.Optimization contains the required classes and will be available right there in the framework, no worrying about external dependancies.
If you are still in MVC3 and want in on the bundling action, the same library is available to you through NuGet, just look for the “ASP.Net Optimization - Bundling” package. It is exactly the same as what will come with MVC4 except that the namespace is “Microsoft.Web.Optimization”
We now have the tools, how do we use them
To fit the majority of cases we need to add one line to the
global.asax file. The line will tell your app that we will use the default bundling rules
With this setup you can now browse browse “[any folder in your site]/js” or “[any folder in your site]/css”. When you browse these it will find all the css or js files in the folder bundle them together, minify them and serve the result as a single file.
So to get your web pages using these new mini bundled psuedo files we add the appropriate link and script tags to our pages
Now our site is using fewer more compact files which will hopefully lead to a faster cleaner website
Keeping it in order
Which order each file appears on the page matters, you dont want to load jQuery after your custom scripts as it wont work, similarly you dont want to load a reset.css after your main site.css as your layout will be reset. How do we tell the bundler our ordering requirements?
Turns out the default bundler is actually quite smart. It knows jQuery (or MooTools or Prototype or a bunch of other frameworks) files comes first. It also knows to use .min.js versions over non min’d versions and it knows to skip .debug.js and -vsdoc files too.
However even with all its smarts there will be times that you know best, and it is these times we have to move away from our single line solution and start explicitly stating the contents of our bundles
When creating a bundle there are a few things you need to to do
- Pass it the relative URL that we will browse to look at the bundled script.
- Pass it the minifier we want to use (usually either JsMinify or CssMinify).
- Add to the list of files that are included in the bundle.
- Finally add our new Bundle to the bundle table.
Now we are in more control of what we are bundling and more importantly the order in which we bundle them.
Are all our minifying problems now solved?
A quick solution to get our real code for debugging and our bundled code for production might be to do something like this in our views
However this going to cause you issues in the future. You are now essentially maintaining the files that are in your bundle at two places, in your
global.asax for production and in your views for debug. Whats worse is if your bundle configurations arent the same you will get different behavior when you build in production from when you build in debug.
A slightly better solution could be to build an HtmlHelper method that will output our single file if in production, and output the individual files in the bundle if we are in debug. And that is exactly what the HtmlExtension methods do below
To use in your views you just need to add the following lines. When in debug it will add individual
<link> tags for each file in the bundle. In production it will add just one that points tag that points to our single minified bundle.
A bit of work is still required to get your environment setup to be debug friendly.
@if(debug) your views provides a simple, but limited solution. Telling the bundler not to minify for debug also provides another way to keep your code intact but still causes a one file output. Finally to stop minifying and bundling an HtmlHelper method can provide the shortcut to writing the
<link> tags for you.