Minifying js and css in nanoc
I found some solutions to minify and concatenate scripts and stylesheets in nanoc, but none of them had the flavor i really wanted, so I baked one up myself.
This solution will allow you to download unminified (development) versions of your javascript libraries and css frameworks, which allows for easier debugging, and minifying them on-demand as you compile your site. It’s leightweight and easi to implement.
For this example i have my css files and js files under /assets/js/
and /assets/css/
respectfully. You can easily change the code to reflect another structure.
We’ll be using rainpress
and uglifier
to minify our scripts and stylesheets respectfully, so we’ll have to install the gem to make that happen.
The easiest way to deal with gems in nanoc in my opinion is to use a Gemfile.
In your application root directory, create a Gemfile if you haven’t already
touch Gemfile
Now open this file with your favorite editor and add the gems rainpress
and uglifier
. Whe using a Gemfile you also have to include nanoc itself.
gem "rainpress"
gem "uglifier"
gem "nanoc"
Install the gems
bundle install
We’ll make two helpers that will concatenate the compiled content of all your scripts and stylesheets. The advantage here is that you can mix css, scss, less … whatever! It doesn’t matter, because the items will pass through compilation before they are concatenated.
Put this code in lib/helpers.rb. Nanoc includes all code in the lib
directory, so this will be available in your app.
def all_js(files)
js_arr = []
for file in files
item = @items.find{|i| i.identifier == "/assets/js/#{file}/"}
puts "File #{file} doesn't exist!" unless item
js_arr << item.compiled_content
end
js_arr.join("\n")
end
def all_css(files)
css_arr = []
for file in files
item = @items.find{|i| i.identifier == "/assets/css/#{file}/"}
puts "File #{file} doesn't exist!" unless item
css_arr << item.compiled_content
end
css_arr.join("\n")
end
These functions take an array of identifiers and turn the compiled content of the files with these identifiers into one long string. Later we will run this content through the minification filters.
In your config file (config.yaml) in the root, add a few directives. The debug
directive turns concatenation and minification on or off. This is helpful if you have to track down typo’s or bugs in the scripts or in the stylesheets. The scripts
and stylesheets
directive contains the filenames (without extensions) of your scripts and stylesheets.
debug: false # if true, don't concatenate scripts
scripts: # your script filenames without extension
- jquery
- main
stylesheets: # your stylesheets files without extension
- screen
- print
- ie
Make two files /assets/css/all.css
and /assets/js/all.js
touch /assets/css/all.css && touch /assets/js/all.js
In all.css put this code:
<%= all_css @config[:scripts] %>
In all.js put this code:
<%= all_js @config[:stylesheets] %>
In your default template (usually default.html), put this code in the head (without the dots please!!):
...
<head>
...
<% if @config[:debug] %>
<% for file in @config[:stylesheets] %>
<link rel="stylesheet" type="text/css" href="/assets/css/<%= File.basename(file, ".*") %>.css">
<% end %>
<% else %>
<link rel="stylesheet" type="text/css" href="/assets/css/all.css">
<% end %>
<% if @config[:debug] %>
<% for file in @config[:scripts] %>
<script src="/assets/js/<%= file %>"></script>
<% end %>
<% else %>
<script src="/assets/js/all.js"></script>
<% end %>
...
</head>
...
The above code makes all your normal scripts appear on seperate link and script statement if debug is enabled in the config.yaml file. Otherwise everything is concatenated ( and uglified / minified ) into one big file: all.js or all.css and that one is used. This kinda mimics the rails assets pipeline on a very low level.
Compile rules (in Rules
):
compile '/assets/css/*' do
filter :erb
filter :rainpress if File.basename(item[:content_filename], ".*") == 'all'
end
compile '/assets/js/*' do
filter :erb
filter :uglify_js if File.basename(item[:content_filename], ".*") == 'all'
end
This runs the all.css and all.js files through the rainpress and uglify_js filters which comes with nanoc.
Route rules (in Rules
):
route '/assets/css/*' do
# if not debug mode, only let all.css through
unless @config[:debug]
item.identifier.chop + '.css' if File.basename(item[:content_filename], ".*") == 'all'
else
item.identifier.chop + '.css'
end
end
route '/assets/js/*' do
# if not debug mode, only let all.js through
unless @config[:debug]
item.identifier.chop + '.js' if File.basename(item[:content_filename], ".*") == 'all'
else
item.identifier.chop + '.js'
end
end
You should now have minification up and running. The real strength of this comes to life when you mix in files with sass or coffescript or something like that. Be aware that you should make changes to reflect this in the Rules file. I will let you fiddle with that yourself. Good luck and have fun with nanoc. It rocks!!!