A Bumbling Bundler: Fixing IncludeDirectory()
16 December 2013
In my post on getting started with ASP.NET MVC’s Bundler, we looked at a couple of methods that allow you to include files and directories to include as part of a bundle. Unfortunately, there’s a serious gotcha with IncludeDirectory()
that we’ll see—and correct!—in this post.
You keep using that word…
Let’s say we have a directory structure like this (in this example, files for an Ember application):
- app
- controllers
- account
create.js
login.js
+
+ routes
Logically, we’d want to include both of the “account” controllers. This can be easily done with a call to IncludeDirectory()
, specifying the full (relative) path and a search filter:
bundles.Add(new ScriptBundle("~/bundles/app") |
This approach is fine for smaller apps with only a few of these “feature“ subfolders, but quickly becomes unmanageable with a more complex system:
bundles.Add(new ScriptBundle("~/bundles/app") |
One option, and the one we’ll discuss here, is to bundle all of the files in all of the folders under ~/app/controllers
together. If you poke around the Bundle
class’s methods, you may notice that the IncludeDirectory()
method has a searchSubdirectories
parameter on an overload that sounds like it would do exactly that.
bundles.Add(new ScriptBundle("~/bundles/app") |
Unfortunately, what’s output isn’t really all that helpful:
<script src="/app/controllers/create.js"></script> |
Can you spot the problem? While all of the path’s subdirectories are searched, the subfolder structure isn’t respected when the bundler compiles the paths to output to the page. Our create
and login
controllers aren’t children of the controllers
folder, but rather its subfolders, so the above references will return a 404 (“not found”) error. (Frankly, I can’t think of a reason why this parameter exists, but if you’ve used it, let me know in the comments!)
Building a better recursor
One potential solution is to build our own directory recursor using DirectoryInfo
. Keep in mind that MVC’s bundler uses application-relative URLs (that begin with ~/
), and DirectoryInfo
needs absolute, file path URLs (e.g. C:\dev\...
). In this implementation, we’re using Server.MapPath()
and a simple string replacement to swap between the two:
public static class BundleExtensions |
Once we incorporate our new directory searching function (implemented as an extension method so we don’t break the option for method chaining), we can organize our files however we’d like, and they come out just fine:
<script src="/app/controllers/account/create.js"></script> |
If you’ve used other ways of including subdirectories in a bundle, or if you have intimate knowledge of why the searchSubdirectories
parameter even exists, let me know in the comments! Happy bundling!