- Keep server roundtrips to a minimum. The techniques for the various resource types are as follows:
- CSS - again merge them as far as possible.
- Images - Use CSS sprites where one combines several images into one and uses the background image offset to display the one you are after. To create the sprites you can always use this online sprite generator.
- Reduce the size of each request. This is done in two ways:
- GZip/Deflate compress text resources by configuring IIS and/or using an ASP.Net HTTP Module.
- Reduce file sizes. The tools I use for each type are:
- CSS - CSSTidy not only reduces whitespace but optimises the CSS expressions as well.
- Images - As PNGs are my image format of choice I use PNGGauntlet to reduce the image file size.
- Ensure resources are cached. If you know that the files are going to change infrequently then all you have to do is set IIS to enable content expiration for a folder/file to expire after a set number of days, say 10. This will ensure that the client browser caches the resources and does not re-download them. However depending on the frequency of your deployments and your server architecture you most likely want to ensure that your etags are setup correctly. These are used to indicate whether or not the cached browser resources have changed. When loading a page the browser will send a request to the server, with the etag, for each resource and if it has not changed then the server will only return a 304 status code. Note that this advice is contrary to Yahoo where they tell you to remove etags for a web farm scenario. What you should rather do is ensure that the etag change number is the same for each server in the web farm. This ensures that the etag generated for the same resource on a different server is the same (how to do this varies depending on your version of IIS - read this post for more IIS6 information). If you are using a single web server however the whole this is a non-issue for you.
<% #if DEBUG %>
<% #else %>
<% #endif %>
For CSS files you can either use the directives around alternative <link> elements or around @import statements, like this:
<% #if DEBUG %>
@import '<%= ResolveUrl("~/Css/File1.css") %>';
@import '<%= ResolveUrl("~/Css/File2.css") %>';
<% #else %>
@import '<%= ResolveUrl("~/Css/CombinedStyles.minified.css") %>';
<% #endif %>
There is a catch to this however, since the aspx pages are compiled separately, setting your application to compile as a release build will not cause the references to change. What you need to do is change the compilation setting in the application web.config file, which should be set to debug="false" in the production environment:
Now on to the merging and minification. This could be accomplished using MsBuild or a batch file, but a batch file is simpler, so I'll discuss that. On one of the build steps for the web site(s) invoke the batch file which then ensures that the optimised files are always up to date. So you want to add something like this to your pre/post build compilation step in the project property window:
I setup the "Build Scripts" folder to contain the optimisation programs as well as text files with lists of files to merge, for example:
In my simplified scenario the "Optimise Web Resources.bat" batch file contains the following:
:: Change to the current directory
cd /d %0\..
::Ensure there are no old temporary files lying around
type AdminCombined.js | jazmin > AdminCombined.minified.js
::Combine the Stylesheets into a single file
for /F "tokens=*" %%f in (CssFilesToMerge.txt) do call type "..\Web Sites\Site\CSS\%%f" >> CombinedStyles.css
csstidy.exe CombinedStyles.css --template=high CombinedStyles.minified.css
copy CombinedStyles.minified.css "..\Web Sites\Site\CSS\CombinedStyles.minified.css"
::Remove the temporary files
::Restore the old "current directory"
chdir /d %OLDDIR%
Hopefully the rest of the batch file is pretty self evident and there is enough information here to get you started on implementing the approach yourself. If there are areas that need more explanation please leave a comment on the blog post.