How to specify file ordering for bundling in ASP.NET MVC?
I’ve been working on a ASP.NET MVC based application to add bundling and minification for the web resources like CSS, JavaScript files. If you would like to learn the basics of this feature, you may read my post where I explain how to bundle, minify web resources in your application. The concept explained in that post is same that applies to an application with or without Areas. In this post, I’ll explain you how to specify file ordering for bundling in ASP.NET MVC app.
There are times when the application needs to instruct the framework about the order in which a bundle should be created for styles and scripts in the application. In simple words, there can be some resource(s) that must be loaded first before others in the browser.
For example, jQuery library must be included before any custom scripts or libraries or plugins that requires it as a dependency. For styles, there are some reset CSS files that needs to be included before any other styles so that file can first apply the same styles across all the browsers and only then include other CSS files.
Let us learn about the ordering by some code examples below.
bundles.Add(new ScriptBundle("~/bundles/appScripts").Include("~/Scripts/*.js"));
The code above instructs the framework to load all the files with `.js` extension to be included in the bundle. In this case, the framework will create a bundle to include the files on the basis of alphabetical order by going through the file names. So, if we have `app.js` and `jquery.js` files in the directory, with no file ordering, this bundle will first load `app.js` and then `jquery.js` which may break the application if the scripts in `app.js` file depends on `jquery.js`. However, this can be resolved by adding file ordering so that bundle includes the files in the correct order.
Default File Ordering
The optimization framework already has default file ordering defined for us. It knows about some of the most commonly used libraries that must be loaded first if found in the bundle’s definition. You can see this default file order in `AddDefaultFileOrderings method defined in `System.Web.Optimization` namespace.
/// <summary>
/// Adds default file order specifications to use with bundles in the collection.
/// </summary>
/// <param name="list">The list to populate with default values.</param>
public static void AddDefaultFileOrderings(IList<BundleFileSetOrdering> list)
{
if (list == null)
throw new ArgumentNullException("list");
BundleFileSetOrdering bundleFileSetOrdering1 = new BundleFileSetOrdering("css");
bundleFileSetOrdering1.Files.Add("reset.css");
bundleFileSetOrdering1.Files.Add("normalize.css");
list.Add(bundleFileSetOrdering1);
BundleFileSetOrdering bundleFileSetOrdering2 = new BundleFileSetOrdering("jquery");
bundleFileSetOrdering2.Files.Add("jquery.js");
bundleFileSetOrdering2.Files.Add("jquery-min.js");
bundleFileSetOrdering2.Files.Add("jquery-*");
bundleFileSetOrdering2.Files.Add("jquery-ui*");
bundleFileSetOrdering2.Files.Add("jquery.ui*");
bundleFileSetOrdering2.Files.Add("jquery.unobtrusive*");
bundleFileSetOrdering2.Files.Add("jquery.validate*");
list.Add(bundleFileSetOrdering2);
BundleFileSetOrdering bundleFileSetOrdering3 = new BundleFileSetOrdering("modernizr");
bundleFileSetOrdering3.Files.Add("modernizr-*");
list.Add(bundleFileSetOrdering3);
BundleFileSetOrdering bundleFileSetOrdering4 = new BundleFileSetOrdering("dojo");
bundleFileSetOrdering4.Files.Add("dojo.*");
list.Add(bundleFileSetOrdering4);
BundleFileSetOrdering bundleFileSetOrdering5 = new BundleFileSetOrdering("moo");
bundleFileSetOrdering5.Files.Add("mootools-core*");
bundleFileSetOrdering5.Files.Add("mootools-*");
list.Add(bundleFileSetOrdering5);
BundleFileSetOrdering bundleFileSetOrdering6 = new BundleFileSetOrdering("prototype");
bundleFileSetOrdering6.Files.Add("prototype.js");
bundleFileSetOrdering6.Files.Add("prototype-*");
bundleFileSetOrdering6.Files.Add("scriptaculous-*");
list.Add(bundleFileSetOrdering6);
BundleFileSetOrdering bundleFileSetOrdering7 = new BundleFileSetOrdering("ext");
bundleFileSetOrdering7.Files.Add("ext.js");
bundleFileSetOrdering7.Files.Add("ext-*");
list.Add(bundleFileSetOrdering7);
}
As you can see there are two default orders for styles and rest are for scripts. So, if a bundle has any of the above file in the definition, those files are included first irrespective of the order where that file is included in the bundle definition. The ordering above is defined logically for CSS reset files, jQuery library (with plugins), Modernizr, Dojo, etc.
Custom File Ordering
Similar to the default file ordering, we can add our own custom file ordering. Use BundleFileSetOrdering type with a unique ordering name to add patterns or name of the file(s) to include first in any given bundle. This order object then needs to be added to FileSetOrderList – a list object accessible via bundles object of type BundlesCollection as shown below:
internal static void RegisterBundles(BundleCollection bundles, string areaName)
{
var appModuleOrder = new BundleFileSetOrdering("angularModules");
appModuleOrder.Files.Add("*.module.js");
bundles.FileSetOrderList.Add(appModuleOrder);
}
In the code snippet above, I’ve added a file order so that the framework will include all of my custom Angular modules first, if, such an entry is found in the bundle definition or when a pattern is used to search for say *.js files in a directory.
It is very useful to add custom file ordering sets in your application like the one above. It can ensure less error when creating a bundle.
The other useful object is FileSetOrderList above which is an IList of type BundleFileSetOrdering. As such this is a list, it can be manipulated like any list and we can also clear any or all of the registered order sets, if needed. It can also be used to modify existing file set orders just like how you insert an item at specific location/index in a list using C#. This can be handy in cases when you don’t want to modify the ordering set and also want to run script before some scripts like jquery.js which exists in default file ordering set. See the code snippet below where we would like to add console.js file before jquery.js file for a bundle.
bundles.FileSetOrderList.First(f => f.Name.Equals("jquery")).Files.Insert(0, "console.js");
This sums up my post that explains how to specify file ordering for bundling in ASP.NET MVC app. Using default or custom file ordering will ensure that the file order will be maintained even when optimization is enabled or disabled. Read the official documentation to explore more about this feature.
