blog

Image of Rabbit

Minification: Smaller Quicker is Better

by

The topic of minification tends to come up in the context of reducing bandwidth usage. After all, if the Internet is a series of tubes with a finite size, its important to keep our contribution small and prevent clogs (Tip: keep your site small, or it’ll get stuck in the U-bend). More realistically, any given server setup will have bandwidth limits that need to be respected, lest additional cost be incurred.

Unless you’re serving your files hundreds of thousands of times per day, however, the 10s of kilobytes saved by minification can seem not worth the effort – especially if you’re trying to convince a client why they should pay for any extra time incurred. And as a developer, if you know you’re already serving those files gzipped, it might seem unnecessary even to you.

What you’d both be missing, in this case, is that minification isn’t just about preserving bandwidth (both server and client), although that is a real benefit (even those few 10s of kb can count – consider your clients on highly constrained mobile data plans). There is another major benefit to minification – reducing time to page responsiveness.

Based on some results from Micrososft Research, it appears that user retention by any given page/site corresponds nicely to a negative aging Weibull distribution, as employed in reliability engineering. There’s a more in-depth explanation of the impact of this research, but the short and sweet version is:

You have 10 seconds to make a positive impact on your prospective user. If you haven’t impressed the user in the first 10 seconds, you’ve lost their attention.

Useful features and good design will win the day, of course – if you manage to present them within that critical 10 second window; thus, you don’t want to spend any more time than absolutely necessary waiting for the page to render and become responsive. Minifying your css and scripts can help with that, by reducing the total kb per file, and reducing the overhead (by combining multiple css/js files into one).

Google’s page speed tools and tips can help identify where you can squeeze some extra time from – it will, for instance, suggest you minify all scripts if you haven’t already done so. It doesn’t get into the how, however. Some frameworks come with tools to assist you with this – I know Rails comes with UglifyJS, for instance – but let’s say you have an existing or new project without these tools already available, and that you’re now sufficiently sold on the concept. Here’s a quick (and not too dirty) approach.

  1. Get Google’s Closure Compiler (and Closure Stylesheets as well, if you want to minify css – also allows for using mixins and conditionals, SASS or LESS-style, if desired). Note that both rely on Java, so if that bugs you, you’ll need to look for another option (something Node based, perhaps?)

  2. Place them into an appropriate directory in your project (/build, for instance).

  3. Create an ini file that contains references to each of the files (and the type of file) that needs to be minified and combined into one.
    It will look something like:

css=common.css
css=more.css
js=first.js
js=seconds.js
js=third.js
  1. Modify the following scripts as needed for your project and dir structure: Note that the shell script is intended for Mac OS – you’ll likely need to make some changes to accomodate your Linux flavour. Also note the closure stylesheets jar has been named closure_css.jar.

CMD

@ECHO OFF
@setlocal enableextensions enabledelayedexpansion
IF "%1"=="--help" GOTO Usage
IF "%1"=="/?" GOTO Usage
REM set defaults
set ini=build.ini
set csspath=../static/css/
set jspath=../static/js/
set jsout=../static/js/compiled.js
set cssout=../static/css/compiled.css
set js=
set css=
:GetParams
REM -- Get command line parameters - see usage to determine what each does --
IF "%1"=="" GOTO GetJavaHome
IF "%1"=="-j" set JAVA_HOME=%2
IF "%1"=="-i" set ini=%2
IF "%1"=="--jspath" set jspath=%2
IF "%1"=="--csspath" set csspath=%2
IF "%1"=="--jsout" set jsout=%2
IF "%1"=="--cssout" set cssout=%2
SHIFT
SHIFT
GOTO GetParams
:GetJavaHome
REM -- Determine where Java is --
REM -- IF JAVA_HOME isnt set, ask the user to give us a path --
IF "%JAVA_HOME%" == "" (
    echo Enter path to Java base directory, where the bin directory resides:
    set /p JAVA_HOME=
)
REM -- We should have JAVA_HOME by now - compile javascript and css based --
REM -- on settings in build.ini --
FOR /F "tokens=1,2 delims==, " %%i IN (%ini%) DO (
    IF "%%i"=="js" set js=!js!--js=%jspath%%%j
    IF "%%i"=="css" set css=!css!%csspath%%%j
)
echo !js!
echo !css!
"%JAVA_HOME%bin\java" -jar compiler.jar --compilation_level SIMPLE_OPTIMIZATIONS !js! --js_output_file=%jsout%
"%JAVA_HOME%bin\java" -jar compiler_css.jar --allow-unrecognized-functions !css! -o %cssout%
GOTO End
:Usage
echo.
echo --Usage--
echo build -j "path/to/java" -i "path/to/ini" --jspath "path/to/js/files" --csspath "path/to/css/files" --jsout "path/to/js/output.js" --cssout "path/to/css/output.css"
echo.
echo --Params--
echo Note: All parameters are optional
echo.
echo -j     Specify path to java, where 'bin' directory resides\
echo -i     Specfiy path and filename of ini file (default build.ini)
echo --jspath   Specify path to the js files whose names are defined in the ini file
echo --csspath  As above, for css files
echo --jsout    Specify output path and filename for the compiled js file
echo --cssout   As above, for css
echo.
:End

Bash

#!/bin/sh
#set defaults
ini=build.ini
csspath=../static/css/
jspath=../static/js/
jsout=../static/js/compiled.js
cssout=../static/css/compiled.css
js=
css=
#Get arguments and set vars appropriately
while [ "$1" != "" ]
do
  if [ "$1" = "--help" ]
  then
     echo --Usage--
     echo build -j "path/to/java" -i "path/to/ini" --jspath "path/to/js/files" --csspath "path/to/css/files" --jsout "path/to/js/output.js" --cssout "path/to/css/output.css"
     echo --Params--
     echo Note: All parameters are optional
     echo -j        Specify path to java, where 'bin' directory resides
     echo -i        Specfiy path and filename of ini file default build.ini
     echo --jspath    Specify path to the js files whose names are defined in the ini file
     echo --csspath    As above, for css files
     echo --jsout    Specify output path and filename for the compiled js file
     echo --cssout    As above, for css
     exit 0
  elif [ "$1" = "-i" ]
  then
     ini=$2
  elif [ "$1" = "-j" ]
  then
     java_home=$2
  elif [ "$1" = "--jspath" ]
  then
     jspath=$2
  elif [ "$1" = "--csspath" ]
  then
     csspath=$2
  elif [ "$1" = "--jsout" ]
  then
     jsout=$2
  elif [ "$1" = "--cssout" ]
  then
     cssout=$2
  fi
  shift
  shift
done
#Read in paths from specified ini file
OIFS=$IFS
IFS="="
while read LINE
do
  set $LINE
  if [ "$1" = "js" ]
  then
     js="$js --js=$jspath$2"
  elif [ "$1" = "css" ]
  then
     css="$css $csspath$2"
  fi
done < $ini
IFS=$OIFS
#Remove leading spaces
js=echo $js|sed 's/^ *//g'
css=echo $css|sed 's/^ *//g'
#Perform compilation
java -jar compiler.jar --compilation_level SIMPLE_OPTIMIZATIONS $js --js_output_file=$jsout
java -jar compiler_css.jar --allow-unrecognized-functions $css -o $cssout
  1. Profit!

+ more