Extreme JavaScript Compression with
          YUI Compressor
               Nicholas C. Zakas
     Principal Front End Engineer, Yahoo!
Who's this guy?
• Principal Front End Engineer, Yahoo! Front Page

• YUI Contributor
• Author
JavaScript
       Minification/Compression
• Problem: Lots of JavaScript
• Solution: Make JavaScript smaller
• Two areas:
  – Wire weight
  – Browser weight
Wire Weight Solution: Gzip



                   Internet




    Server
Wire Weight Solution: Gzip



Internet




                  Browser
Browser Weight
Browser Weight Solution: Minification
 •   Remove comments
 •   Remove extra white space
 •   Identifier replacement
 •   Other...
Minification Tools
• ECMAScript Cruncher (ESC)
  – http://www.saltstorm.net/depo/esc/
• JSMin
  – http://www.crockford.com/javascript/jsmin.html
• Packer
  – http://dean.edwards.name/packer/
• Dojo Shrinksafe
  – http://shrinksafe.dojotoolkit.org/
YUI Compressor




http://developer.yahoo.com/yui/compressor/
About YUI Compressor
•   Remove comments
•   Remove extra white space
•   Identifier replacement
•   Micro-optimizations
•   Built on top of Rhino interpreter
    – Makes all optimizations safe
Mozilla Rhino




• Open source JavaScript interpreter
• Written in Java
• Based on Firefox's interpreter

         http://www.mozilla.org/rhino/
How It Works
Micro Optimizations
The Results

      -44%


      -44%
Helping the Compressor
Best Optimization
            =
Identifier Replacement
    (aka munging)
Identifier Replacement
• Local identifiers only
   – Functions and variables
What Can't Be Replaced
• Primitive values
   – strings, booleans, numbers, null, and undefined
Primitive Values
• Strings take up the most space
• Non-numeric literals take second-most
  – true, false
  – null
  – undefined
• Approach: Any literal value used two or more
  times should be stored in a local variable
Primitive Values



                   263 b




                   172 b
Primitive Values




                   293 b




                   162 b
Prototype
•   79 repeated strings = 1196 bytes
•   80 true/false = 359 bytes
•   44 null = 176 bytes
•   21 undefined = 189 bytes
•   Total primitives = 1920 bytes
•   Potential savings > 1 kb
jQuery
•   96 repeated strings = 1742 bytes
•   107 true/false = 478 bytes
•   46 null = 184 bytes
•   Total primitives = 2404 bytes
•   Potential savings > 1.3 kb
•   undefined = negligible
jQuery
Primitive Variables
What Can't Be Replaced
• Primitive values
   – strings, booleans, numbers, null, and undefined
• Global variables
   – window, document, XMLHttpRequest, etc.
Global Variables
• Most bytes:
  – document
  – window
• Approach: Any global variable used two or more
  times should be stored into a local variable
Global Variables




                   293 b




                   162 b
Global Variables




                   317 b




                   162 b
Prototype
•   49 document = 392 bytes
•   29 window = 174 bytes
•   Total globals = 566 bytes
•   Potential Savings > 500 bytes
jQuery
•   24 document = 192 bytes
•   27 window = 162 bytes
•   Total globals = 354 bytes
•   Potential Savings > 300 bytes
What Can't Be Replaced
• Primitive values
   – strings, booleans, numbers, null, and undefined
• Global variables
   – window, document, XMLHttpRequest, etc.
• Property names
   – foo.bar
Property Names
• Next to repeated strings, biggest source of extra
  bytes
• Anything to the right of a dot cannot be replaced
• Makes a.b.c even more expensive
• Approach: Any property used two or more times
  should be stored into a local variable
Property Names




                 317 b




                 162 b
Property Names




                 291 b



                 144 b
What Can't Be Replaced
• Primitive values
   – strings, booleans, numbers, null, and undefined
• Global variables
   – window, document, XMLHttpRequest, etc.
• Property names
   – foo.bar
• Keywords
Keywords
• Most commonly overused:
  – var
  – return
• Approach: Try to have only one var statement
  and one return per function
Keywords




           291 b



           144 b
Keywords




           308 b



           127 b
The Results
Before:



                                              172 b
After:



                                              127 b
Total Savings (from original) = 136 b (52%)
Total Savings (from final)    = 181 b (59%)
Hurting the Compressor
Preventing Identifier Replacement
• Use of eval() function
“eval() is evil”
-Douglas Crockford
eval() is Evil
eval() is Evil
Preventing Identifier Replacement
• Use of eval() function
  – Solution #1: Don't use it
  – Solution #2: Create a global function that wraps
    eval()
Living with eval()
Preventing Identifier Replacement
• Use of eval() function
  – Solution #1: Don't use
  – Solution #2: Create a global function that wraps
    eval()
• Use of with statement
“with statement
considered harmful”
-Douglas Crockford
with Statement
Preventing Identifier Replacement
• Use of eval() function
  – Solution #1: Don't use
  – Solution #2: Create a global function that wraps
    eval()
• Use of with statement
  – Solution #1: Don't use
  – Solution #2: see Solution #1
Preventing Identifier Replacement
• Use of eval() function
  – Solution #1: Don't use
  – Solution #2: Create a global function that wraps
    eval()
• Use of with statement
  – Solution #1: Don't use
  – Solution #2: see Solution #1
• JScript conditional comments
Jscript Conditional Comments
Preventing Identifier Replacement
• Use of eval() function
  – Solution #1: Don't use
  – Solution #2: Create a global function that wraps
    eval()
• Use of with statement
  – Solution #1: Don't use
  – Solution #2: see Solution #1
• JScript conditional comments
  – Only solution: Don't use
The Compressor Helps You
Verbose Mode
• Use -v switch to enable
• Reports issues with code related to minification:
   –   Undeclared variables
   –   Unused variables
   –   Functions with more than one var statement
   –   Use of evil features (eval(), with, conditional
       comments)
Verbose Mode
Summary
For Optimal File Size
• Use local variables to store:
   – Repeated primitive values
   – Global variables
   – Object properties
• Limit each function to one var and one
  return
• Avoid using eval() and with()
• Heed YUI Compressor's advice
• Combine with HTTP compression for best savings
http://developer.yahoo.com/yui/compressor/
Questions?
Etcetera
• My blog:    www.nczonline.net
• My email:   nzakas@yahoo-inc.com
• Twitter:    @slicknet
Happy crunching!
Creative Commons Images Used
•   http://flickr.com/photos/velkr0/467471030/
•   http://flickr.com/photos/oskay/253010234/
•   http://flickr.com/photos/pacfolly/2304020816/
•   http://flickr.com/photos/blmurch/304690615/
•   http://flickr.com/photos/tshirbert/191179745/
•   http://flickr.com/photos/mc/27061495/
•   http://flickr.com/photos/oberazzi/318947873/

Extreme JavaScript Compression With YUI Compressor