This project is read-only.

Timestamping css file

Topics: General, Writing themes
Feb 10, 2012 at 3:43 PM
Edited Feb 13, 2012 at 9:38 PM

I'm using Style.Include("mycssfile.css") in Layout.cshtml.

I'm wondering how I can timestamp it to prevent css caching when the css has been updated.

So my goal is:

<link href="/Themes/MyTheme/Styles/mycssfile.css?12345" rel="stylesheet" type="text/css" />

"12345" would be my timestamp (or whatever).

Feb 10, 2012 at 6:00 PM

Might be interesting to discuss the possibility of having a .WithTimestamp() on the resource which would add a query string parameter with a hashed update time.

What do others think about that ? How is it handled in other CMSs ?

Feb 10, 2012 at 8:15 PM

It's not a CMS, but I like the way it's done in Cassette:

If you're not in debug mode (via web.config), it just appends a hash of the content as a query string by default. Updated css = new url. No need to explicitly call a method to do it.

But a .WithTimestamp() method would be great too. Whatevs. :-)

Feb 10, 2012 at 8:17 PM

ASP.NET webforms does that too. The problem is that it requires reading that file every time you include it. Timestamp is less costly.

Feb 10, 2012 at 8:36 PM
Edited Feb 10, 2012 at 8:36 PM

Just looked at Cassette and it looks awesome ... but then I realised I'd seen something else recently about 'Bundling':

So before anyone goes and programs anything complicated ... maybe this is something MVC will soon turn the wheel around on? Alas. the Combinator module will suffer some redundancy ... I'm aware some great work has been done on it ... although there are two things to think about, 1) Combinator already gives you a new stylesheet URL if you change the content and 2) perhaps much of the work done on Combinator can actually still be used to integrate Orchard with the new Bundles system ...

Feb 10, 2012 at 9:27 PM

The 4.5 bundling feature looks interesting. I wonder how that would play with the way Orchard uses dependencies to determine script ordering? 

Combinator is solves some of these problems. I believe it changes the name if you change the timestamp of the file, it doesn't check to see if the contents actually changed. Usually that means the same thing, so mostly a moot point. 

If one wanted to get fancy you could use a CacheDependency to watch the static resources and recache them when the contents changed. You could then get away with using the hash of the contents in the bundled/minified file name. Potential gotcha: I'm not sure if CacheDependency would work with the file system of cloud hosts like Azure or Amazon. 

There's another project out there, I think it's called SquishIt that does something similar. Might be worth looking to see how they do it. Cassette requires some xml style comments in the files in order for it to detect dependencies and include them in the right order.

Another problem I had recently was that Combinator isn't used in the admin theme. I made changes to the TinyMce config and deployed them to my staging area. My content editors had some old .js/.css cached and couldn't see any buttons on the TinyMce toolbars. I had to look into it, they reported it as an IE bug at first but finally figured out that they could fix it by clearing their browser cache. Not sure how we should handle that, but Combinator doesn't help in the Dashboard. 

Feb 11, 2012 at 11:38 AM
Edited Feb 11, 2012 at 11:38 AM

Taking a look at Bundling: I think it will be difficult to match the folder-based approach with Orchard's resource management. Nevertheless, since there will be a public API for sure, at least minification could be done with the built-in classes.

I don't think there is a need for a new property for resources: there is the Version already that could be used for cache-busting too. Now that would imply that developers actually set and maintain it (shame on me, I've never used it), so the version number could be appended to the included resource's url when writing to the output.

Combinator actually could be used on the admin site too: it is disabled there currently (you can experiment with it by removing/commenting out the body of Filters/AdminFilter.OnResultExecuting()'s body) but after 1.0 has no problems there. Why I opted to disable it was that it would require some configuration (excluding TinyMCE, CKEditor or other WYSIWYG editors to be specific) and if something gets messed up anyway, it's always frustrating when it happens on the admin panel. In future versions I think I'll include an option to enable it on the admin site too for those who would benefit from it.

BTW today I released a new version of Combinator that includes also the cache busting feature.

Feb 23, 2012 at 5:52 PM
Edited Feb 23, 2012 at 5:53 PM

What kind of configuration is necessary to enable bundling on the admin side, for TinyMce or other WYSIWYG editors? 

Note: I'm testing out the latest version of Combinator now. 

Feb 23, 2012 at 6:29 PM

Wait for MVC 4 :)

Seriously, however, Combinator is great for bundling all the stylesheets and scripts Orchard knows about, the problem with the Javascript editor modules is they usually include a single script and loads of others are loaded behind the scenes by that editor's framework. So you can't really bundle them because you don't know what scripts will end up being included.

Feb 23, 2012 at 6:47 PM

So it will still work, it just won't bundle the dynamically loaded stuff? If so, I can live with that. 

Feb 23, 2012 at 6:55 PM

@TheMonarch: exactly what Pete is saying is the problem with WYSIWYG editors, so the solution is quite straightforward then, just exclude those editors from combination (after you removed the mentioned part that keeps Combinator from running on the admin page). I tried it once and the filter "tiny_mce|slugify" worked for me (the script slugify is that makes a fake publish to get the slug depending on the title - not sure how this works since Autoroute).

Feb 23, 2012 at 7:50 PM

Understood. I got it working and excluded tiny_mce from combination. 

Nice to have: Dashboard/Admin bundling as a separate feature that can be enabled/disabled. It would essentially do the same thing as commenting out AdminFilter.OnResultExecuting(), but we wouldn't have to mess with the Combinator module code to do it. 

Feb 23, 2012 at 8:19 PM

Yeah, I've already opened an issue for it.