Concatenate filter for nanoc
I just love nanoc. It might actually be my favorite way of making websites, because of the flexibility and speed a static site can give you.
One thing I sorely missed, was the option to do on-demand concatenation of asset files, like javascript or stylesheets.
It’s a simple task actually, so I rolled up my sleeves and got coding. I made a filter that will do exactly that. It turned out to be ridiculously easy.
Gotcha’s
This filter can only concatenate files in directories below the one that they are concatenated into. The reason for this being that the use case for the latter is quite rare, and I use nanoc items, so including files outside the project is not possible.
The code
put the following in lib/concat_filter.rb
require 'nanoc'
module Nanoc
module Filters
class ConcatFilter < Nanoc::Filter
identifier :concat
def run(content, args = {})
return unless item[:require]
rel_folder = File.dirname(@item.identifier.chop)
includes = ""
for name in item[:require] or []
included_item = @items["#{rel_folder}/#{name}/"]
includes << included_item.compiled_content + "\n;"
end
includes + content
end
end
end
end
Add the necessary filter to your Rules file:
compile "/assets/js/application" do
# filter coffeescript if item[:extension] == "coffee" # run some coffescript first
filter :concat
# filter uglify # for minification
end
compile "/assets/css/application" do
filter :concat
# filter :rainpress
end
You should now be able to concatenate items by adding them to the header yaml of a css, coffee, or js file. Add them as an array under the name “require”. Add the files without extension. Like this:
assets/js/application.js
:
---
require:
- jquery
- bootstrap
- flexslider
---
alert("some amazing javascript!");
or this:
assets/css/application.css
:
---
require:
- bootstrap
- flexslider
---
body {
margin-top: 60px;
}
Don’t worry, the yaml header will be removed by the authorities! :)
If you want to add files from a subfolder, you just prepend the folder name to the filename, e.g. lib/jquery
or something like that.
I like to block all javascript and css in the Rules, and then only let the concatenated files through. You can do that like this:
# Rules
compile '/assets/stylesheets/application' do
filter :concat
filter :rainpress
end
compile '/assets/javascripts/application' do
filter :concat
filter :uglify_js
end
compile '/assets/(javascripts|stylesheets)/*' do
nil
end
# ...
route '/assets/stylesheets/application' do
"/assets/stylesheets/application.css"
end
route '/assets/javascripts/application' do
"/assets/javascripts/application.js"
end
route '/assets/(stylesheets|javascripts)/*' do
nil
end
In the above example only application.js
and application.css
will be let through, and these two files will be minified as well. Totally ready for production!
The cool thing about this is that it integrates with the filter chain in nanoc. So you run your js through coffeescript (you’d have to do that before runnning the concatenate filter, though, since the coffeescript compiler doesn’t really dig javascript) and minify the concatenated file.
Remember: To run the extra filters above (coffeescript, rainpress, etc.) you’d have to install their gems first.
I hope this post was useful to you, if it was please share or comment!
Cheers!