If you take a look at the HTML source at the CodePlex Issue Tracker page, you’ll see it references 13 WebResource.axd and ScriptResource.axd. That’s 13 different web requests on each page load. The ScriptResource.axd is using HTTP compression but WebResource.axd does not. None of them minifies the scripts.

Therefore it would be cool to create a plug ‘n play HttpModule that combines all resource.axd scripts into one single web request and then minify and compress them. It would result in smaller HTML, fewer web requests and optimized JavaScript code. If you’re a YSlow nazi like me, this is a must-have.

How it works

To make it work, we need both an HttpModule and an HttpHandler.

The module

The module looks for resource scripts in the HTML code and collects all the references from the src tag. It then constructs a new script tag containing all the references and points it to the HttpHandler. The new script tag is injected into the HTML where the first resource script was found. It keeps the order of the scripts intact.

All the original scripts are now removed and a single new script pointing to the handler is injected.

The handler

When the handler is requested by the browser it looks for a URL parameter containing the references to the original resource script. They are separated by a comma in the URL parameter. It then retrieves the content of each script using a HTTP request. Then content is then aggregated into a single string which then get’s minified. Minifying means that all comments and whitespace is removed from the script.

The string is then being cached so the handler only has to do it once per application life cycle. The output is then compressed and the appropriate header set so the browser will cache the file for 30 days. You can easily set the number of days in cache to whatever you see fit.

Implementation

Download the ScriptCompressor.cs file below and put it in your App_Code folder. Then add the following lines to your web.config:

Very nice. However I have a couple suggestions that would make this even better...
1) The CodePlex Issue Tracker page has 13 ScriptResource/WebResource .axd script includes. But it also has 9 other javascript includes in the page too. A neat addition to this would be to combine all of them into a single minified script.
2) Maybe have an option to not combine and minify the scripts when the application is running in Debug. This way it's still a little simpler when debugging.
Just a couple thoughts.

Hi Mads,
Try look at http://www.codeplex.com/MbCompression
I think it does something similar, and if you put your developer skill into improving this project and then use it for BlogEngine.NET, others can use it too (even without Blogengine)
Petr

Hi Mads, Nice idea.
Two things:
The Regex you use in your filter will not match if the type="text/javascript" will come before the src="" part. (as appear in the Blogengine.NET 1.2 release).
Also, if the first WebResource appears in the header (because it contains script for 'onload' event), you will and up with huge script request on the header that will block all the page content until it done. This will perform slower page load than 5 small requests in the page body. The combining must be with more care.

I had to comment out an IF statement to get it to work on HTTPS sites.
void context_BeginRequest(object sender, EventArgs e) {
HttpApplication app = sender as HttpApplication;
if (app.Context.CurrentHandler is Page &amp;&amp; !app.Request.RawUrl.Contains("serviceframe")) {
//if (!app.Context.Request.Url.Scheme.Contains("https")) {
app.Response.Filter = new WebResourceFilter(app.Response.Filter);
//}
}
}

OK last post on this... I also created a version of the ScriptCompressor for CSS. You use it the same exact way. It uses file dependency for the cache so you should be good when things change. I made a zip file with my changes to ScriptCompressor and CssCompressor.
http://files.rushfrisby.com/dotnetrush/code/CompressorClasses.zip
Have fun :-)

Hi mads thanks forthe post
but I have a small problem i able to compress all scripts into a single new script pointing to the handler.
but iam getting an error saying Sys is undefined
please help me out

Hello there! Brilliant idea! Helped me a lot!
Well... for the "Sys is undefined" error, it's very simple =P
The problem is that the link generated (js.axd?path=/WebResource.axd?blablabla) has this damn slash after the "path="! Just had to remove it from the module, something like:
string relative = match.Groups[1].Value;
if (relative[0] == '/') relative = relative.Substring(1);
list.Add(relative);
(Yeah... I know I could have done this in the Regex pattern... but regular expression is one of the things that my brain refuses to understand =P)
AND I needed to add this slash in the handler:
content += RetrieveScript(root + "/" + script) + Environment.NewLine;
Now it's working beatifully!
Cheers!
Cassiano

Hi Mads,
I've been scouring the net for something just like this and surprised at the lack of 'lightweight' options as you have presented! Well done! ... well kinda,.. I can't seem to load any ScriptResource.axd references; The response I get is directing me straight to my login page for authentication. Any ideas?
PS: Thanks Cassiano with the WebResource.Axd splash fix: Worked a treat!
PPS: Thanks Rush for the IE fix, but I can't seem to get the CSS implementation working at all :(
Cheers!

hello everyone,
Thank you everybody for putting your minds into this post, especially, Mads!
i stuck with the problem though, wonder if somebody has a hint/idea how to fix it..
i understand we combining those webresources given that all of them JS.. but how about images? In particular, i am suing ajaxtoolkit tab control and it USES webresources to store there images that it require...
So, there are banch of js errors pop up when i try to look at the page with tab control..
using Response.ContentType == "application/x-javascript" as was suggested ealier does not help (or may be i am using it incorrectly)..
Thanks for any help,
hf

Hi Mads Kristensen
I have used your scriptcompressor.cs file but it didn't work. I got the same error as friends posted above like "Sys is Undefined" in IE and "Sys is not defined" in Firefox. I couldn't do anything in my site. The site was jammed. Please help me how to overcome this issue. Please take a look on this site http:www.anytimerooms.eu which shows an error in IE as well as error console of Firefox.
Advance thanks for your help.
I hope u come with solution asap.

Brilliant bit of code, but I have an issue.
I get a js error Expected ';' and have eventually tracked this down to a missing semicolon in Microsoft's WebForm_DoCallback function
xmlRequestFrame.style.position = "absolute";
xmlRequestFrame.style.top = "-100px"
xmlRequestFrame.style.left = "-100px";
Anybody else come up against this issue?

Hi,
I don't think you need to handle the ScriptResource case. Because in the scriptmanager you can set the scriptmode="Release". It will pick the minified version.
The value by default is set to auto, which will look at the config and see if the debug mode is on or not and set it based on that.

Hi,
I had changed what Cassiano said. But till now also I am getting "Sys is undefined".
[b]This is the script that I am getting from SERVER[/b]
js.axd?path=anytimerooms/WebResource.axd?d=mee-Go1B7DJthBqLdDhfSQ2&amp;amp;t=633598415816665082,anytimerooms/ScriptResource.axd?d=dP1w54zng6-_VbdnzgGa9fmEBpcIf1DhhTcBB_ck8J3DEDIbvQoUmMD4K3K3fHU1qOlAAso9IGan3cllA3y5t7a0iQHaNNd_xKjM4b9_y_81&amp;amp;t=633598434759103750,anytimerooms/ScriptResource.axd?d=dP1w54zng6-_VbdnzgGa9fmEBpcIf1DhhTcBB_ck8J3DEDIbvQoUmMD4K3K3fHU1qOlAAso9IGan3cllA3y5t_OxDBS2tePvdBtJ91BOBF_41ojyWdmT-D2hA8TdHXti0&amp;amp;t=633598434759103750,
[b]This is from LOCAL[/b]
[b]FROM LOCAL I DIDN'T GET THE ERROR[/b]
js.axd?path=WebResource.axd?d=hMGWEcMxH5OxwLGvITx8Bw2&amp;amp;t=633633194134236166,ScriptResource.axd?d=sSIqFd-6lYJr9TEobXdLGR9AdBXO0p8SORUVVzFokmLt6jhhv0a3AcThYf8zcQ_c8R6foqoVOKn4q6HYY5L1kNNRJXYi6BLMxnHI3UU1osk1&amp;amp;t=633633656961406250,ScriptResource.axd?d=sSIqFd-6lYJr9TEobXdLGR9AdBXO0p8SORUVVzFokmLt6jhhv0a3AcThYf8zcQ_c8R6foqoVOKn4q6HYY5L1kOpMqjpvPaTF9NzH48ILqJ01&amp;amp;t=633633656961406250,
Thanks

Possible exploit, although I haven't figured out a use for it yet. Your security check simply checks if resource.axd is in the url not the path, meaning it can be in the query string. Meaning the following can be used to get past the check.
http://website/js.axd?path=/robots.txt%3FRESOURCE.AXD
That said you can only get files that the webserver is willing to serve up, so it can't be used to get the web.config or anything. However the request does count as the webserver itself rather then the user doing the request meaning you may be able to get items you can't normally.
I'm also having another problem with this seeing as my web host seems to limit the length of my query strings. I tried compressing the querystring with no real results, so I was considering caching the current querystring and using a Guid instead but that wouldn't exactly be ideal (or reliable if the cache dies). Anyone have some brilliant idea around this?
(Accidentally posted this comment on the wrong page http://blog.madskristensen.dk/post/Optimize-WebResourceaxd-and-ScriptResourceaxd.aspx)