Mike Niebling

Setting up Jekyll on Github Pages with LESS

One cool thing about Jekyll is that it comes out of the box with SASS support. However, if your preprocessor of choice is LESS, there’s a bit more work involved to get that in place. My goals for this blog were:

  1. Get LESS working instead of SASS.
  2. Make sure it doesn’t break Github Pages hosting.
  3. Create one command for running the blog locally, that does both whatever bundle exec jekyll serve does plus compile & live reload the LESS on changes.

The complicating factor is that I am a lowly designer and know very little about this sort of stuff. Here are some of the options I looked at and the narrative of how I got it into place with no previous Ruby dev/build experience.

Before any of this, the very first thing I did was to change my CSS to vanilla LESS and and link the site against a compiled CSS file that doesn’t exist yet. Of course, this broke all styling, but once the compilation is running, at least I’d be able to tell it worked!

Plugins

The easiest option to get LESS working on Jekyll is probably to use its plugin system, which augments how Jekyll generates the site. Unfortunately, hosting on Github Pages only allows whitelisted plugins and at the time of this post there isn’t one for LESS.

Commit hooks

Some pretty smart folks have solved this by adding a Git commit hook that compiles the LESS to CSS whenever a commit happens. However, I’m lazy, so I’d like to have compilation and reload happen locally on any change, not just when I commit.

Luckily, it turns out other lazy programmers have come before me and built some cool technology called task runners, which can watch local files for changes and then do stuff like concatenate, minify, hint or compile.

Let’s use Gulp?

I have a tiny bit of experience using Gulp on one of my side projects, so that’s where I looked first. Buuuut it’s in the Node/npm universe, and it felt like it would be better to stay on the Ruby side of things instead of introducing a bunch of javascript dependencies into this project. So I pinged a Ruby buddy and he pointed me towards Rake instead.

Let’s use Rake

Having decided on Rake, step 1 was to get it added to the project. The Rake docs have helpful instructions (gem install rake, duh) but I wanted to make sure that was automated when Future Me wants to set up the repo on a new machine or something. So it should probably go in the Gemfile instead.

I headed over to RubyGems and found the gem, then added it to the Gemfile: gem 'rake', '~> 10.4.2'. I took a few minutes to figure out what the pessimistic operator is because I’d never seen ~> before. Then I committed the gemfile change, cd to my project directory and did bundle install to get the Rake gem. To confirm it worked: bundle show rake. Yup, there it is!

Need a LESS compiler too

So now I could run tasks, but I needed something to handle the actual compilation step. I headed back to rubygems and found the LESS gem, then added it to the Gemfile as well. However, as I discovered when I tried to run my first Rake task, there’s one more dependency once LESS is in play. Because LESS uses Javascript, Rake needs something that will allow JS and Ruby to talk to each other. This something is TheRubyRacer, and I had to go add that gem as well.

Once that was all done, the next step was to set up the Rake task to do the compilation. The first Google result I found was this helpful Gist from Pedro Figueiredo. Since I didn’t speak Ruby too well, I struggled through changing the path names and trying to figure out what I was doing. Here’s my heavily commented and slightly tweaked version of that original Rakefile: (gist).

Awesome! Now, I could do rake compile_less from the command line and it would correctly build and copy the LESS over to the target CSS file. But, I wanted this to happen automatically! So… onwards.

Automating the LESS compilation task

The gem I decided to use for this was Guard. However, when I started reading the Guard docs, they seemed completely confusing. It seemed like Guard would let me handle the compilation itself, but all I wanted to do was run my fancy new Rake task when a .less file changed.

So I did a bit more Googling and found something that seemed relevant: guard-rake. Awesome! I had Guard installed, so I went ahead and Gemfiled guard-rake, then did guard init rake, which automatically created a starter Guardfile in my repo root for me.

To get the Guardfile watching the correct stuff was a bit of a pain, because it uses regular expressions to set paths. I ended up with this (note I also changed the name of the Rake task to compile_less):

guard "rake", :task => "compile_less" do
    watch(%r{^web/less/.+\.less})
end

I tested this by running bundle exec guard init, changing a LESS file, and watching the compilation task fire. Awesome! Now all that was left was to get rid of the Guard terminal and stitch Guard and Jekyll together so everything would run with one command.

Making everything run with one command

This actually seemed like a lost cause until I found the guard-jekyll-plus gem. Installing this allowed me to set up a second Guard task like so:

guard "jekyll-plus", :serve => true do
  watch /.*/
  ignore /^_site/
end

This task, with :serve => true included, causes Guard to spin up the Jekyll server when it starts. So when I run bundle exec guard, it now starts the Jekyll server, watches for LESS changes with the rake guard and watches for any other changes with the jekyll-plus guard. And I can still commit the normal master branch and let github pages build the site without any special configuration. Perfect!!

If you want to see the finished implementation, check out the project repo here.