random .NET and web development musings

Recently I posted about how you can split your CSS up into separate files, and use a NAnt task to combine them on build to aid development.

This can be very useful, but theres still room for improvement.

The YUI Compressor is a brilliant tool to remove whitespace and other bloat from your scripts which take up valuable bandwidth. Combining it with an automated build tool such as NAnt allows you to have all your scripts minified automatically on deployment.

Here are two example build tasks for minifying JavaScript and CSS respectively:

<target name="compress-js">
	<foreach item="File" property="filename">
		<in>
			<items basedir="output/build/assets/javascript/">
				<include name="/**/*.js" />
				<exclude name="/**/*.min.js" />
				<exclude name="/**/*.pack.js" />
			</items>
		</in>
		<do>
			<exec basedir="." program="${JavaPath}java" commandline=" -jar ${YUICompressorPath}yuicompressor-2.4.1.jar --type js --charset utf-8 -o &amp;quot;${filename}&amp;quot; &amp;quot;${filename}&amp;quot;" failonerror="true" />
		</do>
	</foreach>
</target>

<target name="compress-css" depends="combine-css">
	<foreach item="File" property="filename">
		<in>
			<items basedir="output/build/assets/css/">
				<include name="/**/*.css" />
				<exclude name="/**/*.min.css" />
				<exclude name="/**/*.pack.css" />
			</items>
		</in>
		<do>
			<exec basedir="." program="${JavaPath}java" commandline=" -jar ${YUICompressorPath}yuicompressor-2.4.1.jar --type css --charset utf-8 -o &amp;quot;${filename}&amp;quot; &amp;quot;${filename}&amp;quot;" failonerror="true" />
		</do>
	</foreach>
</target>

Using this in combination with my CssCombiner, I achieve an average of 70% compression!

Enoy :)

One of the most difficult aspecs of web development today is managing and maintaining your stylesheets. Typically you have a single huge file, divided into sections by comment blocks (if you’re organised). Navigating to the group of styles you need to edit typically involves Ctrl-F and lots of inside knowledge. Individual CSS developers tend to have their own quirks when it comes to the internal organisation of their “monolith.css”. Some like to separate structure and layout from colour and style whilst others like to define all attributes for a selector in a single place. The result of all these different, typically unmanaged techniques can make it very difficult for maintenence developers to get to grips with legacy stylesheets, surely there must be a solution?

Take a look at this CSS from a recent project I worked on…



css-organisation

default.css contains:

@Import url(Reset.css);
@Import url(MainLayout.css);
@Import url(Components/Header.css);
@Import url(Components/Misc.css);
@Import url(Components/WhiteBox.css);
@Import url(Components/Forms.css);
@Import url(Components/BaseModal.css);
@Import url(Components/CustomModal.css);
@Import url(Components/Popup.css);
@Import url(Components/DefinitionList.css);
@Import url(Components/ResultMessage.css);
@Import url(Components/ShipmentCalendar.css);
@Import url(Components/Severity.css);
@Import url(Components/Document.css);
@Import url(Components/ResultsTable.css);
@Import url(Components/TaskList.css);
@Import url(Components/TodoList.css);
@Import url(Components/ContractList.css);
@Import url(Components/ShipmentList.css);
@Import url(Components/EditIcons.css);
@Import url(Components/UserList.css);
@Import url(Components/SimpleList.css);
@Import url(Components/ApplicationForm.css);
@Import url(Components/jquery.ui.css);
@Import url(Components/Blank.css);
@Import url(Components/thickbox.css);

Each file in the components folder contains just a few lines of related styles, on the topic of the filename.

The more astute among you may have realised however that whilst this mass of @Imports might be super useful for development, its going to create an HTTP request spamathon on each page request.

Step up my CSS combining NAnt task.

As an aside, I am currently migrating towards Rake instead of NAnt as my build tool, and when I do I shall create a Ruby version of this.

Point the task at your CSS files, and it will run over them, replacing each @Import directive with the CSS that would actually be imported. Awesome! This means you can divide your CSS up into a million, super granular files and not need to worry about any HTTP request overheads, because in the live environment, you will only have a single file :D

To use the task:

  1. Import the dll into your .build file
  2. Point the CssCombiner task at your built CSS files (NOT YOUR SOURCE CODE)
  3. Go and do something else with the time you have saved

Here is an example:

<loadtasks assembly="./tools/CssCombiner.NAntTask.dll" />

<target name="combine-css">
    <CssCombiner>
        <fileset basedir="output/build/">
            <include name="/**/*.css" />
		</fileset>
	</CssCombiner>
</target>

Enjoy :)