Switching Ghost From Ruby Sass to Libsass

In the early days of Ghost, any CSS was written in Sass, which meant Ghost had a Ruby dependency. In March of this year, the Sass was moved to its own repository, which meant Ghost no longer had a Ruby dependency, but had 2 repositories instead. A couple weeks ago, we decided to take the plunge and adjust our Sass so Libsass could compile it. This is why.

There were plenty of other reasons to switch to a new repo, besides the lower dependencies:

  1. It was intended to make Ghost-UI a library available for general conception, like Bootstrap and Foundation.
  2. As such, separate issues between Ghost and Ghost-UI
  3. We wanted to share styles between Ghost and Ghost.org

This worked well for a while. Many people who contributed regularly knew what goes where and how we had split the two, but there were still a few who (rightly so) didn’t quite get it or missed the memo.

Additionally, it made it much tougher to implement a feature that needed both HTML, JS and CSS. You’d need to make 2 pull requests – one for each repo – and discussion would happen in different places. Or, someone will do the Ember.js part and I’d do the CSS part, which is typically what happened. Pull requests needing minor changes were roadblocked on me.

Now there are plenty of reasons to move it back into Ghost:

  1. Libsass exists, which can be run in Node.js via Node-sass (which is a wrapper) and grunt-sass, which is also much faster
  2. We didn’t do a great job at making Ghost-UI a reusable library – I personally think it doesn’t lend itself well to other projects anyway
  3. We had duplicated issues in both repos or single issues in the wrong repo
  4. We realised sharing styles between Ghost and Ghost.org its a great idea – both achieve different goals.
  5. People can work on CSS at the same time as their Ember.js stuff. Sounds primitive now I say it like that, doesn’t it.

How We Did It

The way we did this might not be conventional, but it works.

  1. Remove any Ruby dependencies and Gems
  2. Add grunt-sass (which bundles its own dependencies, including libsass) and adjust Grunt build tasks
  3. With grunt watch running, save it, see where it fails and replace that Bourbon mixin with un-prefixed code or add the mixing to our own file
  4. Do that for a couple hours and finally have a compiling code-base, via Node-sass!
  5. Add Autoprefixer via grunt-autoprefixer and configure

Here’s what you need for the Grunt tasks. It’s simplified from what we use. I’m not going to explain how wire it up, I trust you’ll know where to put these.

// package.json
"grunt-autoprefixer": "1.0.1",
"grunt-sass": "~0.14.0"
// Gruntfile.js
sass: {
    compress: {
        options: {
            style: 'compressed',
            sourceMap: true
        files: {
            'ghost.min.css': 'screen.scss'
autoprefixer: {
    options: {
        map: true, // Use and update the sourcemap
        browsers: ["last 2 versions", "> 1%", "Explorer 10"]
    single_file: {
        src: 'ghost.min.css',
        dest: 'ghost.min.css'

Woop woop! We now have the same code-base (maybe even slightly smaller) with cleaner, prettier code.

“replace”? “Bourbon”?

Yes. Bourbon had been been in Ghost from very early on. I guess it was added in hope we’d use it lots. But the truth is, we only used it for prefixing things, and for the occasional helper like clearfix and triangle.

What’s the point of keeping it and having @include’s all over the place, for such a small benefit? We can bet better results with nicer code by using Autoprefixer.


Hannah Wolfe (Ghost’s CTO) wrote a good issue detailing some of the other issues we’ve had, so that’s definitely worth a read if you’re interested.

Aside form the other benefits I’ve mentioned above, the move back into Ghost means we do longer have to deal with Bower and release tags.

The compile time is reduced from about 10 seconds to an average of 3 seconds (at least on my machine – your machine may be faster). With a ~5-6 second saving, hundreds of times a day, it really adds up.

All the issues and commit history in Ghost-UI were also moved back into Ghost, which is some kind of magic that Hannah did. Mind: blown.

“Was It Hard?”
Not really. A bit time consuming, but so worth it.

“Would I Do It Again?”
Sure. Not that I need to, but it only took a couple hours.

“Do you want cake?”
All of it. Can I eat it?

Get Angry

Not a day goes by without someone – or something – wreaking havoc on the internet. It’s usually spread on Twitter, where the character limit imposes a lack of context. Nobody can fit a good, solid argument into 140 characters. And spreading that argument over several tweets doesn’t work either, because people selectively retweet the parts that interest them, meaning others who read it have even less context, and it continues on and on.

Whether you want to be part of the argument is your choice. The way I see it, you have two options:

  1. Don’t say anything. Let it move down your stream and forget about it.
  2. Get involved, keep involved and stand your ground whilst keeping you humility.

There is nothing worse on Twitter than chiming in on an argument then leaving it. It’s like seeing a bar fight between other people, throwing one punch, and walking away. What good does that do?

I admit that I’m somewhat guilty here. I have chimed in on arguments before, and its rarely ended with me walking away having left a positive impact – I just settle into the background with my tail between my legs.

Over the past few months, I’ve been making a conscious effort to not get into arguments or incite any sort of dislike to specific people. I’ve slipped once of twice, but I’m really trying.

What has that resulted in? I’ve unfollowed a lot of people who seem to get a kick out of licking others bullshit, and blocked people who constantly create bullshit. My stream is now much easier to keep up with and be positive with. Any other bullshit that creeps in, is quickly drowned out by the non-bullshit nice people share. It may be circumstantial, but I feel my attitude towards Twitter has changed for the better – I’m happier with it than I was before.

I feel that’s because I’m exposed to less bullshit in total, so I can tolerate the small amount that gets through. Having a positive attitude makes it easy to not be affected by negativity. The more negativity seen, the harder it is to ignore. In this case, ignorance is bliss.

So what am I getting at? Well, I’m choosing to not get angry by filtering out the right stuff and refusing to get involved in others bullshit.

I’m choosing to not get angry.