By default the Rails 3 asset pipeline uses the Uglifier gem to optimize and minify your Javascript. One of its many optimisations is to remove all whitespace, turning your Javascript into one very long line of code.
Whist removing all the newlines helps to reduce the file size, it has the disadvantage of making your Javascript harder to debug. If you've tried to track down Javascript errors in minified Javascript files you'll know the lack of whitespace does make life harder.
Luckily there is a simple solution: to configure Uglifier to add newlines back into the code after it performs its optimisations. And if you're serving your files correctly gzip'd, the newlines add only a small increase to the final file size.
You can configure Uglifier to add the newlines by setting the following in your Rails 3 config/production.rb
file:
# Ensure this only runs in the :assets bundler group
if defined? Uglifier
config.assets.js_compressor = Uglifier.new(
# Add new lines
:beautify => true,
# Don't add indentation
:beautify_options => {:indent_level => 0}
)
end
You'll notice we have to tell Uglifier not to indent the code. By default it reindents the entire source using 4 spaces per indent, which can add many more bytes than simply adding newlines. And though indentation does make it more readable, it won't really make your life easier when tracking down production errors, and as you'll see below is probably not worth the cost.
YUI Compressor can also be configured to do this by specifying --line-break 0
.
Google Closure Compiler unfortunately has no such option.
Below are comparisons of the different Uglifier options against a fairly large Rails application consisting of 142 Javascript and Coffeescript assets.
For this application the assets:precompile
task generates a single application.js
file, as well as a corresponding application.js.gz
file. We use the .gz
version to compare file sizes, as this represents the final download size that the end-user will experience (that is, assuming your server is set up correctly).
First we find the baseline file size by disabling Uglifier optimizations altogether:
config.assets.compress = false
The resulting application.js.gz
size: 244KB
If left to its own devices, Uglifier removes all the whitespace. This is the default Rails configuration, and results in the smallest file size, but with all your code on a single line.
The resulting application.js.gz
size: 140KB
Telling Uglifier to add only newlines:
if defined? Uglifier
config.assets.js_compressor = Uglifier.new(
:beautify => true,
:beautify_options => {:indent_level => 0}
)
end
The resulting application.js.gz
size: 148KB
The cost of adding the newlines was 8KB which, considering the benefits, is probably worth it.
If you wanted really pretty code you can omit the :indent_level
option and let Uglifier reindent the code using 4 spaces per indent:
if defined? Uglifier
config.assets.js_compressor = Uglifier.new(
:beautify => true
)
end
The resulting application.js.gz
size: 159 KB
The cost of retaining newlines /and/ indenting the code was 19KB, as opposed to 8KB for newlines only.
If you are using a Javascript error tracker, or you want to more easily debug Javascript code on production, then configuring Uglifier (or your asset compiler of choice) to include newlines gains you quite a lot for a relatively small size increase.
In the future source maps might save the day, allowing you to minify and recompile your Javascript to your heart's content, but given neither Uglifier nor CoffeeScript can generate source maps (yet) your best option is to simply include those newlines.
Looks like there is a new options api, so I think now you want:
There is also the
:preserve_line => true
option but it seems useless in the assets pipeline.