Earlier this year, we realized that the Sass compilation time for our application was way too long. Every time we made a CSS tweak, it was taking nearly 8 seconds to compile the assets. This was both extremely frustrating, and a major drag on dev time.
Enter SassC-Rails
While doing some research on how we might be able to speed up our compilation times, I came across LibSass, which is a C++ port of Sass. Given that it’s written in C++, it’s far faster than the original Ruby implementation.
Over the past few months, I’ve been working on a set of gems that brings LibSass to the Rails Asset Pipeline. I’m happy to announce that I’m now releasing SassC-Rails 1.0.0! This is intended to be a drop in replacement for Sass-Rails.
We’ve been using this in production for several months now, and it’s working great. Please check it out and contribute some patches or report any issues you come across!
Speed improvement
In the larger project that I’m working on, we saw compilation become 4x faster!
# Using sassc-rails
[1] pry(main)> Benchmark.bm { |bm| bm.report { Rails.application.assets["application.css"] } }
user system total real
1.720000 0.170000 1.890000 ( 1.936867)
# Using sass-rails
[1] pry(main)> Benchmark.bm { |bm| bm.report { Rails.application.assets["application.css"] } }
user system total real
7.820000 0.250000 8.070000 ( 8.106347)
Bonus: Inline Source Maps!
With SassC-Rails, I’ve also provided a very easy interface for turning on source maps:
# config/environments/development.rb
config.sass.inline_source_maps = true
The nice thing is that these source maps are inline. They will not generate additional files or anything like that.
Instead, they will be appended to the compiled application.css
file.
A bit about the project
First of all, the LibSass project is awesome. The C API is clean and easy to use, and because it’s depended on for porting Sass to other ecosystems (i.e. node-sass, perl-libsass, etc), the development & release progress has been very steady.
Luckily, when I started in on this project many of the last “major” issues had been resolved.
As I mentioned before, I created a pair of gems: SassC-Ruby and SassC-Rails.
SassC-Ruby: Using LibSass from Ruby
The first thing that I need was LibSass bindings for Ruby. There is a project under the Sass organization, ruby-libsass, however it seemed a bit lacking after checking out the code. It was using an older version of LibSass, and wasn’t released on RubyGems.
I went ahead and wrote my own LibSass binding gem, SassC-Ruby. It was written using Ruby FFI against the latest LibSass version, and is well tested. As I said before, the LibSass API is extremely good, so this wasn’t too difficult. I took some inspiration for node-sass for the tricky parts.
SassC-Rails: Integrating into the Rails Asset Pipeline
With some up-to-date LibSass bindings in hand, I started integrating into the Sprockets / Asset Pipeline. Unfortunately this wasn’t quite as easy as I had expected, given that Sprockets isn’t really modular and Ruby Sass is hardcoded into it.
I started by pulling down Sprockets, replacing Sass with SassC, and working through the spec failures until everything passed. This ironed out a lot of the initial inconsistencies.
After I knew that the bindings were working reasonably, I cloned Sass-Rails and got started on moving it over to SassC. This basically consisted of:
- Using SassC instead of Sass to compile the CSS
- Ensuring that the Rails custom Sass functions were working properly (things like
asset_path
,asset_url
,image_path
, etc) - Writing a custom importer that handles ERB, Sass, Scss, vanilla CSS, glob imports, etc. I had some help with this! (Thanks William)
With all of this in place, I took our large Rails project started compiling the CSS with SassC-Rails to work out the remaining bugs. We’ve been using it in production for a few months now, with no issues.
Thanks for reading!
If you have any questions or comments tweet me @bolandrm!
I plan to follow this up with some more in-depth posts about how SassC-Ruby & SassC-Rails work. Be sure to follow me if you’re interested!