Performance Zone is brought to you in partnership with:

I am developer and technology maniac who is working on Microsoft and PHP technologies. I have ASP.NET MVP title and I hold MCAD, MCSD and MCTS certificates. When I have free time I usually play with new technologies, hack something, read books, participate in communities and speak in events. I am also active blogger and my ASP.NET blog is the place you can find some interesting reading about my discoveries and personal thoughts. Gunnar is a DZone MVB and is not an employee of DZone and has posted 141 posts at DZone. You can read more from them at their website. View Full User Profile

Bundling and minifying in ASP.NET MVC

02.07.2013
| 4314 views |
  • submit to reddit

Bundling and minifying in ASP.NET is powerful feature that helps you to optimize your web sites and save some expenses on traffic. As any other machinery in this world, bundling and minifying is not silver bullet and it has it’s own limitations. In this post I will show you how bundling and minifying works in ASP.NET MVC.

What is bundling and minifying?

Bundling helps you to download files of same type using one request instead of multiple requests. This way you can download styles and scripts using less requests than it takes to request all files separately. Minifying helps you make files smaller by removing unnecessary whitespace.

Together these two lessen the amount of requests and bytes to get page loaded by browser.

How bundling and minifying works in ASP.NET MVC

In ASP.NET MVC 4 web application you can find BundleConfig.cs file under App_Start folder. This file contains BundleConfig class that has only one method – RegisterBundles(). In this method files that must be downloaded with one request are added to bundles.

public static void RegisterBundles(BundleCollection bundles)
{
     bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                 "~/Scripts/jquery-{version}.js"));
  
     bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                 "~/Scripts/jquery-ui-{version}.js"));
  
     bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                 "~/Scripts/jquery.unobtrusive*",
                 "~/Scripts/jquery.validate*"));
  
    // Use the development version of Modernizr to develop with and learn from.
    // Then, when you're ready for production, use the build tool at 
    //http://modernizr.com to pick only the tests you need.
    bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                 "~/Scripts/modernizr-*"));
  
    bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));   
   
    bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                 "~/Content/themes/base/jquery.ui.core.css",
                 "~/Content/themes/base/jquery.ui.resizable.css",
                 "~/Content/themes/base/jquery.ui.selectable.css",
                 "~/Content/themes/base/jquery.ui.accordion.css",
                 "~/Content/themes/base/jquery.ui.autocomplete.css",
                 "~/Content/themes/base/jquery.ui.button.css",
                 "~/Content/themes/base/jquery.ui.dialog.css",
                 "~/Content/themes/base/jquery.ui.slider.css",
                 "~/Content/themes/base/jquery.ui.tabs.css",
                 "~/Content/themes/base/jquery.ui.datepicker.css",
                 "~/Content/themes/base/jquery.ui.progressbar.css",
                 "~/Content/themes/base/jquery.ui.theme.css"));
}

Here all files in each bundle are concatenated together and downloaded as one file. It means that this method defines the following URL-s to download files:

  • ~/bundles/jquery
  • ~/bundles/jqueryui
  • ~/bundles/jqueryval
  • ~/bundles/modernizr
  • ~/Content/css
  • ~/Content/themes/base/css

Take a good look at file definitions. You can see that you can specify files not only by name but also by name pattern. Special placeholder {version} in file name means that file name may contain version number. This name pattern is specially good for jQuery that is updated often. When you replace your old jQuery file that has version number in its name with newer version then you don’t have to rename the file. It is enough when file has different version number in its name.

NB! In debug-mode bundling is switched off by default. To force bundling in debug-mode add the following line in the beginning of RegisterBundles() method:

BundleTable.EnableOptimizations = true;

If you open _Layout.cs view of your application you can see how style and script bundles are included to page:

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

Although we have more bundles defined these are there for using with pages where they are actually needed.

ScriptBundle and StyleBundle

If you noticed then script bundle and style bundle have different classes. ScriptBundle is targeted to scripts and you shouldn’t add any other files to script bundles. Same with styles goes for StyleBundle. Both of these classes extend general Bundle class that offers bundling functionality.

Taking care of minifying is tricky. Neither of these classes have no functionality like this. All they do is they add correct minifier to their transforms collection. There are two minifying classes defined in System.Web.Optimizations namespace:

These are the classes that make the actual work. Same way can everybody write minification transforms one needs and if it is desired to keep same style as built-in bundles then one can create new bundle class that adds custom minifier to transforms collection when new bundle is created.

Switching off minifying

Yesterday I found out that CssMinify gets stuck with some style files. In the case of problems bundlers write problems out as comments to file they are transforming. Problems are reported in the beginning of file. While developers try to find out what is wrong with those style files we cannot keep minifying turned on for styles but we still want bundling to work.

There are two ways how to do it.

  • Use Bundle class. Bundle class that other bundling classes extend is not abstract class. We can create instance of it. This way we can bundle whatever files we want.
  • Clear transforms collection of StyleBundle. Clearing transforms collection is same as using Bundle class with empty transforms collection.

Tips and tricks

Here are some tips and tricks related to bundling.

  • Bundles are cached. If not specified differently in bundle class then bundle is created on first request and cached on server. All following requests for bundles are served from cache.
  • Always test bundling. Bundling may seems like what-can-go-wrong feature. You just turn it on before deploying your system to production. But don’t forget these to transform classes I introduced. These classes may face unexpected situations they are not able to handle. Before deploying your system to production make sure that bundling and minifying works like expected.
  • Be careful with styles. When bundling style sheets make sure that bundle path is same “deep” as style sheet path. If style sheet refers to images or other styles using relative URL-s and you change depth of path then all these references are broken.

Conclusion

Bundling and minifying is powerful feature that helps us optimize our web pages. Bundles are easy to use and they are supported out-of-box. Actually almost all ASP.NET MVC templates use bundles. Thanks to easy and flexible API we can control almost every aspect of bundling. Also we can create our own custom bundle types and define custom transforms that are applied to files in bundles. Although bundling is very good it has its own limits and tricks you must know to use them successfully. Good thing is – there are only few things that can go wrong.

Published at DZone with permission of Gunnar Peipman, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)