devroom.io/drafts/2010-09-28-precompile-sass-to-css-for-deployment-to-heroku.md

68 lines
3.4 KiB
Markdown
Raw Normal View History

2013-03-22 22:53:57 +00:00
---
title: "Precompile SASS to CSS for deployment to Heroku"
kind: article
slug: precompile-sass-to-css-for-deployment-to-heroku
created_at: 2010-09-28
tags:
- git
- haml
- sass
- heroku
---
If you have deployed apps to Heroku you know that you cannot write to the read-only file system that Heroku offers. For file uploads you have to use some storage provider like Amazon S3 or RackSpace CloudFiles.
Now, if your application (I'm assuming you're already on Rails 3), is using Haml + Sass, you're in some trouble. Sass is set to generate CSS files on the fly and save them to `public/stylesheets` so the can be served like static content. On Heroku, that is not possible.
Luckily, there are a few solutions to this problem. I'll describe one of them.
~
**Use the Force (of git)**
In my solution I'm using the power of git to generate the necessary CSS files and commit them automatically. Here's how it works.
In a normal situation the Sass plugin will compile the SASS or SCSS files in `public/stylesheets/sass/*.scss` and store the generated CSC files in `public/stylesheets`. What we need to do is generate those CSS files by hand and commit them just like other versioned files in our repository. To do this, you need to write a `pre-commit` hook for git. This sounds more difficult than it really is.
Here's the `pre-commit` hook I'm currently using to take all `public/stylesheets/sass/*.scss` files and store the resulting CSS files in `public/stylesheets`.
:::ruby
#!/usr/bin/env ruby
Dir['public/stylesheets/**/*.scss'].each do |sass|
basename = sass.gsub(/public\/stylesheets\/sass\//, '').gsub(/\.scss$/, '')
next if basename.match(/^_/) # skip includes
css = "public/stylesheets/#{basename}.css"
puts "Compiling #{sass} -> #{css}"
system "sass #{sass} #{css}"
system "git add #{css}"
end
Store the above Ruby script in `.git/hooks/pre-commit`, then give is execute permissions with `chmod 755 .git/hooks/pre-commit`.
This script will find all `*.scss` files and save their `*.css` equivalents. Then it also stages those files for the commit. Since this is a `pre-commit` script, the scenario is like this:
1. You stage your files to commit, like usual and run the `git commit` command.
2. Before git makes the actual commit, it runs the `pre-commit` script, which generates the necessare CSS files. You'll a message like `Compiling public/stylesheets/sass/app.scss -> public/stylesheets/app.css`.
3. With any changes to the CSS stages, your commit is made.
**Won't this spam a lot of CSS commits?**
No, it won't. Git is smart enough to see there are not changes to the content of the CSS file.
**Does it work?**
Yes, it works. The generated CSS files are deployed to Heroku like normal, static CSS files and will be served as such.
**One more thing...**
By default, Sass is set to generate CSS files when needed. Since the CSS file is already there Sass *probably* won't try to generate it again in production. But, it might try so anyway and cause an exception.
To prevent Sass for generating CSS in production completely, add the following line to your `config/environments/production.rb`.
:::ruby
Sass::Plugin.options[:never_update] = true
**Notes**
There is one problem with this approach. If you have multiple developers or machines you work on, each and every one must have this `pre-commit` script installed to make it work. My advise would be to include the script in your project's doc directory.