Imagine coming into work on your first day as a front-end designer or dev and getting your Rails development system up and running for the first time. You’re really excited to start working on something in the app or website that you’re responsible for. After firing up Terminal or a Git GUI, you pull down the latest code and start making some changes to the stylesheets. It just so happens that the stylesheets are written in Sass and they’ll need to compile somehow. Since you are using Rails, that would be the asset pipeline. You hit save and go to the browser, hit refresh…
Anyone that has worked on a Rails project using Sass knows that compile time can get painful pretty quickly. When I came onboard at Treehouse I realized that we were in that boat. When I went in to start making my first style changes I had to wait 30 seconds for the page to refresh. I didn’t realize what caused it at first, but eventually learned it was the stylesheets compiling that were bogging things down. Once we started working on the redesign or our marketing site and other things, this compile time got all the way up to 50 seconds at times.
When I was coding the new marketing skin, I actually added a separate stylesheet to load intoso that I didn’t have to wait for the huge one to compile each time I hit save and refresh. It’s not very good practice to load that many stylesheet on a large production site, but it was worth it to be able to work without waiting so long between each compilation.
Something had to change
As the months went on I decided that at some point we’d need to clean up what was going on in these stylesheets. I’d startup small projects with a few of my coworkers to slowly chip away at organizing our Sass and making things a bit more sane. Part of this even included deleting assets from v1 of our marketing site and app. Yikes! As I was going through this process, the compile time wasn’t really changing. The more I cleaned things up, the more I expected things would compile faster. I moved styles into smaller partials, deleted unused code, etc. Just this week I got our marketing stylesheet down to a single stylesheet again and deleted the secondary one. I figured that if I forced myself to feel the true pain, I’d find a solution faster.
I started doing some research online and stumbled across some blog posts that mentioned using sprockets instead of @imports for Sass partials. I wasn’t sure if this was a good solution or not, but the way Sprockets worked had me curious. I read more documentation on Sprockets and embarked on a journey to give them a try in our stylesheets. I’d have tried anything at this point.
Sprockets to the Rescue
The asset pipeline treats Sass @imports differently that it treats Sprockets. In the case of imports, each save will go through and compile all the imports each time, no matter which partial you’ve saved. The way that Sprockets are treated inside stylesheets is that only the partial you’ve saved will recompile and then be injected onto the page locally when you refresh. Sprockets are the default way of loading multiple partials into a single file for production. We were already using this for our JS, but the stylesheets used Sass imports instead.
The only slightly annoying thing about this is that you then need to import all your non-code-outputting partials, like variables, mixins, etc at the top of all the partials so that they have access to them. You cannot import them above a sprocket manifest reference, it won’t work. Although this seemed annoying at first thought, it actually makes things really simple and flat. When you open a partial, you can see what it has access to right away. If you need it to have access to the animation gem, just @import animation at the top and its ready to go.
After getting all the stylesheets converted and adding in all the necessary imports, I began testing how it effected compilation. You won’t believe the difference it made. This change will probably have a larger impact on our front-end development than anything else ever has. Once I changed a file and refreshed the page I wanted to jump for joy, giddy like a school boy. The page compiled and refreshed in only a 2-3 seconds! That’s an improvement of 47 seconds. This is huge.
To put this change into perspective a bit. If I was spending my whole day in code, changing styles or adding new pages, I might refresh 50 times in a day. This is in no means exact. If each compile was taking an average of 50 seconds before, that’s about 41 wasted minutes per day, and about 164 wasted minutes per 4-day work week, and 656 minutes per month, and 7,872 minutes per year. That’s almost 16.4 8-hour work days per year! Across a design team of 9 designers, that could possibly be 147.6 work days wasted in a year across the entire design team. When you only work a 4-day work week you have to be more efficient, so the new 2-3 second compile time is much better!
Now our designers, and any other designer/front-end dev that happens to read this blog, can save the sanity of their entire team by thinking twice about how they’ve compiled stylesheets in the app or site they are working on. Don’t just let things be as they are, always challenge and refactor things you’ve done in the past.
Thanks for post Chris. After experiencing the same issue in dev, I made the change with our team’s sass setup. Our page loads after CSS changes have definitely sped up alot.
One thing you didn’t mention, though, is the increase in build time when pre-compiling assets. Importing compass mixins on every stylesheet seems to add a lot of time to our CI builds. Even being explicit and importing only specific mixins (ex @import ‘compass/css3/user-interface’) adds a lot time to our pre-compilation.
This could be instant if you only recompile your changes. Also, if you hot-deploy the changes, they would appear instantly and live.
I use a node dev server watching various locations, when CSS changes, it looks through the generated dependencies and recompiles only what’s needed; using Sass or whatever the source was coded in (supports Compas, Less, TypeScript, Pug, ClojureScript, etc).
I use a Socket.IO connection to hot push the changed CSS, which gets swapped out in the correct tag per module (generated in dev, becomes app.css in prod), and viola: All connected clients instantly see the change the instant you save your code. The whole process takes less than 50ms on a local setup and about 150ms for connected phones/etc. No more refresh in the first place 🙂
WebPack is trying to achieve this without any special effort (just download and use sources like you regularly would) and has it working to a great extent too.
3 seconds per refresh x 50 per day x 9 devs x 4 days x 52 weeks = 9.75 days lost to refresh.
I also still use @import without any workarounds; don’t modify your source; modify your toolchain! 😀
Are you using Rails at all? With Sprockets, it’s not easy to just move everything to a JS build toolchain, specially if you are working on an existing large code base like Treehouse.
Which blog post did you got this from exactly?
I’ve had the same experience with slow @imports in my Rails projects, and using Sprockets has been a god-send. There are ways to speed this up even further, by @import-ing only the portions of big libraries that you actually need. Here’s my workflow for super-fast livereload on Rails:
You can use a build process to avoid this. I use gulp which takes about 30ms to compile my scss with 30 imports, which gives me almost instant livereloads
Haven’t seen this approach for very interesting. I tend to have all my
CSS compiled from sass ahead of time in a separate CDN project
which avoids this issue.
I don’t think I have had this problem just yet. I usually have the rails project locally on my machine? All seems to work instantly I believe.
I gave up on using sass in the asset pipeline for this exact reason, switched over to just grunt (and now gulp) and it’s been so much faster and easier.
There is a problem with the social bar on the left of the page when scrolling. Scroll fast and we can see 2 at at the same time 🙂 specially If we scrolled down to Designers rejoiced! using mouse wheel :).
You should try libsass compiler instead of Sass native one, it will be as fast as using sprockets, I promise! =) Anyway, thanks for the article!
I had the same problem when I was on a compass project with many @import.
Switching to libsass it’s a fantastic idea to speed up the compling time. I can’t imagine my workflow without libsass.
I’m working on a project, using right now, LESS + Grunt ( live reload ) , with a huge amount of imports, and less files. At the time I’ve saved the file and go to browser, it’s compiled already.
When I said a huge amount I mean like bootstrap+60 less files with a lot of vars, mixins and nested rules … Like 500kb of css each compilation… It takes a couple seconds.
Never heard that problem neither…
I have never heard of that problem before – but I can imagine, that it is a problem that may occur at some point. But so far, It hasnt happend to me locally. I use CodeKit in my process, and I am importing more then 20 partials at my current project. Some of these partials have more then 1500 rows of scss. But so far the compiling still doesnt take any longer then 1 sec.
Maybe this is a rails related thing, because its actually the first time I hear about that problem. Good to know though!
I don’t work in a large production environment, but this is good to know. It’s definitely going to become my choice for including partials. Thanks for the info!
I do have a quick question, though: To confirm, you’re using @import to import your variables and mixins at the top of every partial, correct? Why are you requiring the _variables partial as well?
Ah, that is most likely a typo that I didn’t notice when making the image. I’ll fix that to avoid confusion.
Just out of interest, is this a problem that only occurs when you rely upon Rails to compile your Sass files? My experience of Rails is limited, but I use Sass in most web projects I undertake, only I tend to use the command line approach, i.e.
sass –watch scss/styles.css:css/styles.css
and I’ve never noticed it taking more than a couple of seconds to compile, even when I have got a few @import statements in the mix. (Although it’s quite possible that your projects are more complex than mine.)
I haven’t tried our project outside of Rails, but I’d imagine you’d see a slow down too if you started importing like 20+ partials.
Not sure that assumption is correct. I’ve come in on a project with an _enormous_ number of SASS partials, over 60. It’s not Ruby, just a JS framework, compiled with Grunt, which has a watcher that runs SASS when updating. Initial build of the SASS takes less than 3 seconds. Updates are much faster.
Of course, compile time will also be related to your processor, so comparisons aren’t necessarily that helpful, but FYI I’m on a 3.2GHz i5 iMac with 16GB RAM.
Definitely Tim! I’ve still loved sass the entire time, I just HAD to get rid of the pain we were all feeling when working locally. Glad you’re also a Sass convert!
Thanks Chris. Hopefully this will put the joy back into SASS. I started developing with SASS last year and never looked back. But as you have observed, more complex projects rapidly start bottle-necking in compilation. Definitely going to give this a go.