Web design, SQL, and .NET for the young, up-and-coming developer Dot Net Yuppie

Yahoo’s Best Practices for Speeding Up Your Web Site recommends minimizing the number of HTTP requests during the delivery of a webpage because there is a significant amount of overhead during the HTTP request process for each file. Furthermore, CSS and Javascript file sizes can be “minified” by removing unnecessary characters, white space, comments, etc. The downside to combining files and minifying, though, is that it becomes very difficult to debug or maintain minified code. To get the best of both worlds, it is best practice to keep two copies of each file — a combined/minified version (for deployment) and a non-combined, readable version (for development). While this process would be labor-intensive with each build, we can implement a few simple tricks in Visual Studio to automate this process and achieve a faster end-user experience.

Step 1: Download CSSMin and JSMin

In order to minify your CSS and Javascript content, you’ll need to download two tools that will automagically remove all of the extra (unnecessary) characters in your code files.  Each of the tools can be downloaded for free at the following developer sites: cssmin-js and jsmin.  For the purposes of this article, I have saved both files (cssmin.js and jsmin.exe) into my “Tools” directory in visual studio (c:\Program Files\Microsoft Visual Studio 9.0\tools).

Step 2: Rename your CSS Files

In order to automate the process of minifying our CSS, we need to do two things: specify which CSS files should be minified and specify the order in which the stylesheet files will be combined.

  1. Specifying target CSS files: As you can see in the image on the right, I have renamed all of my development (readable) CSS files to have a “*.debug.css” filename pattern.  Later, when we enter the syntax for the cssmin-js command, we will ask that only the files with this pattern are minified/combined.  Using this method, we could have the option to have other CSS files in our “style” directory, and if we don’t specify a “*.debug.css” file pattern, they won’t be targeted with cssmin-js.
  2. Specifying the order of CSS files: Depending on how you have configured your stylesheets, you may want certain stylesheet properties to be higher or lower in the combined document.  By using a numerical convention (eg, “01-” starting at the top of the combined file, “04-” at the bottom), we can have control over the order in which CSS files are included into the combined stylesheet file.

Step 3: Rename your Javascript Files

Similarly to our CSS renaming structure, we will need to rename our Javascript files in the same way.  Again, note that all Javascript files that I want minified end in “*.debug.js” and start with a number to maintain the order in which the files are combined.

As you can see below, “04-jquery.qtip.2011-10.min.js” does not end in the structure of “*.debug.js”.  For whatever reason, I encountered problems when minifying and combining this file into a single bundled file.  Because the file does not end in “debug.js”, it will not be minified and combined like the other Javascript files.

Step 4: Specify your Server-side CSS/JS Includes

On many of my ASP.NET-based websites, I extensively use MasterPages in order to reduce redundant code, including CSS/JS include statements.  As I stated earlier, the goal of the project is to maintain readability during development, but minify/combine for deployment.  This can be accomplished in a MasterPage by specifying two different conditions within the <head> tag:

<% If (HttpContext.Current.IsDebuggingEnabled) Then%>
	<link href="<%= Page.ResolveUrl("~/style/01-global.debug.css") %>" rel="stylesheet" type="text/css" />
	<link href="<%= Page.ResolveUrl("~/style/02-grid960.debug.css") %>" rel="stylesheet" type="text/css" />
	<link href="<%= Page.ResolveUrl("~/style/03-codaslider-2.0.debug.css") %>" rel="stylesheet" type="text/css" />
	<link href="<%= Page.ResolveUrl("~/style/03-jqueryui-1.8.12.debug.css") %>" rel="stylesheet" type="text/css" />
	<link href="<%= Page.ResolveUrl("~/style/04-jquery.qtip.debug.css") %>" rel="stylesheet" type="text/css" />
<% Else%>
	<link href="<%= Page.ResolveUrl("~/style/css-bundle.min.css") %>" rel="stylesheet" type="text/css" />
<% End If%>

<% If (HttpContext.Current.IsDebuggingEnabled) Then%>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/01-jquery-1.6.1.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/02-jquery-ui-1.8.12.custom.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/03-jquery.easing.1.3.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/03-jquery.coda-slider-2.0.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/03-jquery.ui.selectmenu.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/03-jquery.jslatex.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/03-clincalc.debug.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/04-jquery.qtip.2011-10.min.js") %>"></script>
<% Else%>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/js-bundle.min.js") %>"></script>
	<script type="text/javascript" src="<%= Page.ResolveUrl("~/js/04-jquery.qtip.2011-10.min.js") %>"></script>
<% End If%>

The HttpContext.Current.IsDebuggingEnabled property allows us to determine whether the current application is being debugged (development) or is being viewed as a deployment build. If debugging is enabled, the MasterPage will serve the individual files in readable format.  In contract, if not in debugging mode, the MasterPage will serve minified, combined CSS/JS files to the end-user.

Step 5: Specify Build Events for “css-bundle.min.js” and “js-bundle.min.js”

The end goal is to automate the process of combining and  minifying our CSS/JS files because it would be very time intensive to manually complete the process each time a change occurred.  To automate the process, we can have Visual Studio execute a post-build event via command line.

  1. To access the post-build events setting, go to Project > [YourProjectName] Properties… >”Compile” tab (on the left), “Build Events…” button (bottom right)
  2. From the “Build Events” window, you need to specify the “post-build event command line”.  Note that your directory structure may differ from mine.
  3. The “post-build command line” syntax, which generates both css-bundle.min.css and js-bundle.min.js, is:
    type "$(ProjectDir)js\*.debug.js" | "C:\Program Files\Microsoft Visual Studio 9.0\Tools\jsmin" > "$(ProjectDir)js\js-bundle.min.js"
    type "$(ProjectDir)style\*.debug.css" | cscript //NoLogo "C:\Program Files\Microsoft Visual Studio 9.0\Tools\cssmin.js" > "$(ProjectDir)style\css-bundle.min.css"
    

Final Wrap-up

If everything goes well, all “*.debug.js” and “*.debug.css” files will be minified and combined into two single files during the Visual Studio “build” process.  Best of all, the minifying and combining process is automated each time the project is rebuilt.  Also, by using the HttpContext.Current.IsDebuggingEnabled property, we can maintain readability of our code for code maintenance purposes.

If you’re interested in seeing this process in action, check out my website with clinical tools and calculators for medical professionals – ClinCalc.com.

Leave a Reply