With websites and web applications becoming increasingly complex, having thousands of lines of Javascript and CSS split over many files, it is important to ensure your CSS and JS files are being sent to users in the most efficient manner.

There are a number of steps involved in providing assets to clients efficiently. This entry covers one of them: combining and compressing. The primary aim is to reduce the number of (HTTP) requests made to the webserver while serving assets and to reduce the bandwidth consumed in delivering them. In the simplest form, we do this by combining all our CSS and all our Javascript into single files, compress the text by removing redundant whitespace and comments and/or running code optimisation routines, and finally send them gzipped. The latter takes place, if supported by the end-user, to further compress the files when they’re sent over the wire from the webserver to the end-user.

We could do all this from the very start of developing a new project, but this introduces great pain into the development process. It’s nigh on impossible to debug combined code compressed to a single line of text, and a massive headache to manage and work with in multi-developer situations under revision control. So, in this case, compression and combining—“combressing” perhaps!—should always take place just before code is put into a production environment, leaving development with fully commented, uncompressed code. Thus ‘combressing’ (I’m going to patent it) should be scripted so that it’s a simple one-click process to push these special live-only assets to live servers.

  1. Combine files to a single file
  2. Compress files using our method of choice
  3. Configure our webserver to send the files gzipped
  4. Modify the codebase to make development easier

Combining

The first step, combining, is a simple process. On Linux boxen, we use the cat command and on Windows we can use the copy command. Both are roughly equivalent commands. Note that the process is identical for both CSS and JS, bar the file extension.

Combining on Linux (.sh)

We con_cat_enate all files together at once and push the output to one file ‘tmp.js’.

#Code
0001 JSDIR="./www/js"
0002 
0003 echo "1. Combining Javascript"
0004 
0005 # Combine all the javascript to a single temporary file
0006 cat $JSDIR/mootools-1.2-core.js \
0007 $JSDIR/mootools-1.2-more.js \
0008 $JSDIR/functions.js \
0009 $JSDIR/common.js > $JSDIR/tmp.js

get this code

Combining on Windows (.bat)

We copy each file on to the previous and push the result to one file ‘tmp.js’. Note that each line must copy the previous tmp.js to the next file, and then save to tmp.js again. As ever, Windows makes life overtly verbose for the developer.

#Code
0001set folder=..\www\js
0002copy/b %folder%\mootools-1.2-core.js %folder%\tmp.js
0003copy/b %folder%\tmp.js + %folder%\functions.js %folder%\tmp.js
0004copy/b %folder%\tmp.js + %folder%\common.js %folder%\tmp.js

get this code

Compressing

I choose to use the Y!UI compressor as it tends to produce the best overall compression results in combination with gzipping, while being a lot less brutal in actual code optimisation routines (for javascript) and being able to compress CSS too. Other options for javascript exist, such as /packer/ and JSMin. Your mileage may vary!

The following commands are from a Linux script, but are identical for Windows except directory slashes should be \.

Compressing JS:

#Code
0001# Compress the combined javascript
0002java -jar ./assets/yuicompressor/yuicompressor.jar --type js -o $JSDIR/combined.js $JSDIR/tmp.js

get this code

Compressing CSS requires just a change to the type flag:

#Code
0001# Compress the combined CSS
0002java -jar ./assets/yuicompressor/yuicompressor.jar --type css -o $CSSDIR/combined.css $CSSDIR/tmp.css

get this code

At this point there should be two files, a combined.css and a combined.js, You should note a marked difference in file size between the uncompressed files and the finished version.

Reducing Bandwidth Consumption with gzip

This part isn’t essential, but it helps a great deal and gzip-encoding is supported by most modern web clients. Even after combining and compressing, you can see anything from 40%-60% reduction in bandwidth consumption per file! For example, employed on beardscratchers.com, 22KB of javascript drops down to a tiny 6KB!

Naturally this comes with a little bit of processing overhead as it’s performed on-the-fly, so beware of using it on everything. It’s somewhat of a topic all of its own, so I’d like to point you towards my del.icio.us gzip+compression page, which will be updated with the most useful resources I find on the subject. Currently the best reading is at:

Easing the Pain of Development

How can we make this easier to deal with? Is there one fire-and-forget method for this? The answer is no. In my experience, the best practice is twofold:

  • Script the combining and compressing, and make it part of your deployment process. On personal projects I use a simple bash script and run it while my FTP client fires up. While professionally it’s employed into the build processes, and checked for errors (yui compressor returns parser errors).
  • Modify your web site/app code so that it conditionally loads the CSS based on the hostname or some other flag indicated by the environment/configs.

By example, I’ve modified my Textpattern templates here to conditionally load CSS based on the hostname aided by the aam_if_host plugin.

#Code
0001<txp:aam_if_host name="beardscratchers,bl">
0002 <link rel="stylesheet" type="text/css" media="screen,projection" href="/css/master.css" />
0003<txp:else />
0004 <link rel="stylesheet" type="text/css" media="screen,projection" href="/css/combined.css" />
0005</txp:aam_if_host>

get this code

My master.css contains a list of @import statements, importing all the separated CSS files during development.

This is only a brief overview; it can get quite complex when you’re dealing with conditional comments for CSS, loading CSS for individual browsers (these shouldn’t be combined), or wish to implement lazy/on-demand loading of Javascript. But hopefully it’s a good starting-point for improving the efficiency of serving CSS and Javascript on the web.

Comments for "Compressing CSS and Javascript with Y!UI Compressor"

Commenting is now closed for this article

  1. For windows copy source1.js+source2.js+source3.js output.js works as well. Windows isn’t overly overtly verbose if you know how to use it ;-)

  2. Heh, unfortunately I am often guilty of making unnecessarily sly digs at Windows. However, the rationale behind my ‘verbose’ comment is twofold:

    1. copy isn’t multibyte aware [I use UTF-8] when combining text files. So you must combine in binary-mode with the /b option. Without it, files are concatenated, but left with dodgy EOF characters that makes the YUI compressor choke and output a merged file that causes a number of rendering problems.

    2. Windows batch scripts don’t provide a clean way to extend scripts over multiple lines (unlike \ in *nix shell scripts). So, while this isn’t needed, when you’re combining 15+ files in a multi-developer environment it’s a lot more readable and manageable to place each file on a new line. The only obvious way to achieve this on Windows is to combine the file one at a time, line by line.

    So, while copy source1.js+source2.js+source3.js output.js will works absolutely fine, it’s not a multibyte safe or particularly optimal solution.

About

beardscratchers.com is a music-focused web experiment and creative-arts journal from London, England.

Subscribe/Syndicate

Categories

Previous Entries…

Journal content and design are © of Nick Skelton

built with web standards and a baseline.