Sorting a ScriptBundle based on /// <reference /> tags

If you’re using ASP.NET Optimization to combine and minify your JavaScript or TypeScript files, you’ll notice that the bundling framework will put certain known scripts first (e.g. jQuery) and then sort the remaining ones alphabetically. However, if some scripts have dependencies on other scripts, you’re often forced to specify an explicit order and turn off the sorting.

Both Visual Studio’s JavaScript edtior and the TypeScript compiler use /// <reference /> tags to specify dependencies between files. I’ve just published a NuGet package, Arraybracket.Bundling, which includes functionality to order the scripts based on those /// <reference /> tags.

Using the package manager console:

Install-Package Arraybracket.Bundling

Then, if you’re using /// <reference /> tags for JavaScript intellisense or for TypeScript dependencies, then just change your ScriptBundle to use ScriptDependencyOrderer.

For example, let’s say your app.ts file references helpers.ts, which in turn uses jQuery. The required order would be:

  • scripts/libs/jquery-1.9.1.js
  • scripts/helpers.ts
  • scripts/app.ts

In scripts/app.ts:

/// <reference path="helpers.ts" />
/// <reference path="modernizr/modernizr.d.ts" />
if (!Modernizr.vwunit)
	onLoadOrResize(() => console && console.log("perform some fallback layout resizing"));

In scripts/helpers.ts:

/// <reference path="libs/jquery.d.ts" />
function onLoadOrResize(handler) {
	$(window).on("resize", handler);

In Global.asax.cs or BundleConfig.cs:

var scriptBundle = new ScriptBundle("~/scripts/combined");
scriptBundle.Transforms.Add(new JsTransformer()); // if you're using Bundle Transformer
scriptBundle.Orderer = new ScriptDependencyOrderer();

If you run your website in debug mode, you’ll see the scripts included in the expected order. If you go into web.config and turn off debug mode, you’ll see the combined file still has the correct order.

Name Matching and Exclusions
You’ll also notice that the example above showed helpers.ts referencing a file called jquery.d.ts, whereas the bundle included a file called jquery-1.9.1.js. The ScriptDependencyOrderer applies some naming conventions to make sure things like JavaScript intellisense files and TypeScript declaration files (whose filenames won’t exactly match bundled scripts) are detected correctly.

The example also references Modernizr as a dependency, but no Modernizr script is included in the bundle. Normally this would show an error indicating that name matching could not match a /// tag to a bundled script. However, Modernizr needs to be included in the <head> tag and can’t be part of the bundle, so ScriptDependencyOrderer knows to exclude it.

You can read more about Name Matching and Exclusions in the README on GitHub or by looking through the unit tests.

License and Source
Arraybracket.Bundling is licensed under the MIT license. The source code is available on GitHub.

2 Responses to Sorting a ScriptBundle based on /// <reference /> tags

  1. Pingback: Les liens de la semaine – Édition #21 | FrenchCoding

  2. mwijnands says:

    This is just too smart. Great idea!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: