This post was migrated from Justin’s personal blog, 'Codethinked.com.' Views, opinions, and colorful expressions should be taken in context, and do not necessarily represent those of Simple Thread (and were written under the influence of dangerous levels of caffeination).

I just pushed up a few minor changes to Bundler, my framework for combining and compressing JavaScript and Css, I also fixed a few bugs and cleaned things up a bit. The big thing I added was named bundles. I personally don’t have a huge need for this feature currently, but I have worked on sites in the past where this sort of thing would come in handy. Let’s take a quick look at how it works…

Support For Named Bundles

With Bundler the way it works by default, we just specified a bundle like this:

Bundle.Css()
    .Add("~/css/first.css")
    .Add("~/css/second.css")
    .Render("~/css/output.css");

The problem was that I was assuming that you could put this in a master page or somewhere that you would only have to specify this once. In my case this is mostly true. I have, however, had to work on sites in the past where it would be impossible to get a bundle of files into only one place. Because of this I decided to create what I call "Named" bundles. The idea would be that you would create a bundle in a single place (such as your global.asax file in app start) like this:

Bundle.Css()
    .Add("~/css/first.css")
    .Add("~/css/second.css")
    .AsNamed("Bundle1", "~/css/output.css");

And then whenever you need one of those named bundles rendered, you could just do it like this:

Bundle.Css().RenderNamed("Bundle1");

Simple enough. I’d still recommend that you try and refactor your site so that you really only need bundles in a single place, but if this is not possible, then bundles might be exactly what you need.

Support For The Css Media Attribute

One other small change I made was to support the Css media attribute. It just looks like this:

Bundle.Css()
    .Add("~/css/first.css")
    .Add("~/css/second.css")
    .WithMedia("screen")
    .Render("~/css/output.css");

I hope you get a chance to go check it out by heading over to the Bundler download page on GitHub.

20 Comments

Claus

After up grading to 0.4, I keep getting an error on my javascript bundle code that an item with the same key has already been added. I’m adding only two (different) JavaScript files, I’m in Debug mode in VS2010.
Any ideas?

Reply
Viktor Bergman

When using this code:
<%Bundle.Css()
.Add("~/css/site.base.css")
.Add("~/css/site.headers.css")
.AsNamed("Bundle1", "~/css/output.css"); %>
<%Response.Write(Bundle.Css().RenderNamed("Bundle1"));%>

Bundler does not render output.css, instead it renders:

<link rel="stylesheet" type="text/css" href="/css/site.base.css" />
<link rel="stylesheet" type="text/css" href="/css/site.headers.css" />

Should’nt it render:
<link rel="stylesheet" type="text/css" href="/css/output.css" /> ?

Reply
Justin Etheredge

@claus I think I might know what I did. I’ll look into it soon.

@viktor Do you have debugging turned on in your web.config? If so, it renders the files normally to allow for easier debugging.

Reply
Claus

Justin – looks like you done fixed it! I’ll let you know how it holds up…Thanks!

Reply
Claus

Justin – just also tested in Release mode on the server and get this exception whether I use virtual (~/scripts) or regular (../../scripts). Works in debug mode. Any ideas? Thanks!

[HttpException (0x80004005): Cannot use a leading .. to exit above the top directory.]
System.Web.Util.UrlPath.ReduceVirtualPath(String path) +11359135
System.Web.Util.UrlPath.Reduce(String path) +171
System.Web.VirtualPath.Combine(VirtualPath relativePath) +214
System.Web.HttpRequest.MapPath(VirtualPath virtualPath, VirtualPath baseVirtualDir, Boolean allowCrossAppMapping) +204
System.Web.HttpServerUtility.MapPath(String path) +252
Bundler.Framework.CssBundle.Render(String renderTo, String key) +246

Reply
Justin Etheredge

@Claus I can reproduce the error, but only if I do what it says, which is to use a ".." to back up past the top level of the website. What do your script references look like?

Reply
Claus

Justin, looks like the problem was that some of my .Add calls had files with version numbers like so:

.Add("~/client/scripts/cw.mediaplayer.js?v=1")

Took them out, now it all works, thanks!

Reply
Justin Etheredge

@Claus Hmm, I would think that this should still work though. Must be a problem mapping that url with the query string parameter to a file on disk. Could you log that as a bug in GitHub.

Reply
Miguel

Hello,

I am using TinyMCE on a MVC project and on the JS code that initiates the TinyMCE code I need to specify the location of a CSS file.

I am using Bundler with AsNamed instead of Render to compress the CSS file and give it the key "TinyMCE".

To reference that file in my JS code should I just add the url or maybe some other way?

What about the "r=…" part?

Thanks,
Miguel

Reply
willabee

In your original command line version, you had the option to include a text file in a directory of files and load order, plus an option to request from a URL. Is there any chance you could re-enable these options in the next version?

Reply
Justin Etheredge

@willabee I was attempting to accomplish something similar with the named bundles, but that still requires you to make changes in the code. The named bundles let you specify your includes in one place and then render them out by just specifying a name.

The folder option would still require you to have to add a new file, include it in the "ordering" file, and then you would still have to go into your project to use the javascript. Is there some big advantage that I am missing here? I’m not saying I won’t add it back in, but I want to make sure that there is some key advantage in doing it this way.

Reply
Gene

First, thanks for this, it is very useful and I like the simplicity. However, I’m also having an issue with the debug line, such that this works once the project gets to production, but does not work in release mode on my dev machine.

In a VS 2010 project, where the web.config file is updated from the web.debug.config and web.release.config files, iun this case

compilation debug="false"

is replaced during a release build from the web.release.config file, using

<compilation xdt:Transform="RemoveAttributes(debug)" />

In this situation, (only for a build on my dev machine in release mode, when using publish to push a release version of the project to another a production directory it works properly), née Bundler outputs all the css files as if still in debug mode.

If I manually edit the web.config file to

compilation debug="release"

Bundler outputs the proper combined css file (I have not tested if the behavior is the same with javascript, but I assume so).

<link rel="stylesheet" type="text/css" href="/content/css/combined.css?r=DDEDD872E958CDE0A10C3BE655F648A7" />

If there is no easy fix, then just a note to explain would save some time debugging.

Reply
Gene

I think the behavior is explicable in that the web.release.config file doesn’t remove the compilation debug attribute just by switching to a ‘release’ build — you need to publish the project in some form. Otherwise, even in release mode the web.config stays as debug="true".

Does Bundler rely on the web.config compilation debug attribute? Or does it look at whichever project/solution file visual studio sets the build configuration (as displayed in the project | properties | build | configuration | Active(Release).

If web.config then to get this to work on an inplace release compile, you would have manually set compilation debug="false" in web.config.

Again, works in production, so perfectly usable, only confusing when doing a release build on my machine and expecting to see the nicely combined css file.

Reply
Chris

Justin, awesome work dude. I got it working in about 10 minutes. Quick question – how would I use conditional comment css and js includes inside the Bundle.Css and Bundle.Js calls? Thanks again for your work.

Reply
Justin Etheredge

@Chris I think you could use it in conditional comments just fine, but they would have to be a separate bundle. Just put the comment tags around the output tags from SquishIt/Bundler.

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *