Sass/Compass & Acquia

Compass makes CSS so much easier and and also makes it very easy to make sure your CSS is complete. With embedding and the CSS3 plugings taking advantage of newer CSS3 features and have them fallback in much nicer ways.

I have liked it so much that I have started using it on all of my projects. For my bigger clients I use Acquia's cloud hosting which I really like and also fits my work flow much better with git. However they do not support the native sass/compass plugins to be able to compile my css on the server.

Yes I could use scssphp and sassy to compile on the server, but I don't think that it compiles the css as well as the ruby version, and also I will always know that it will behave correctly. This is mostly personal choice, so I need to compile all the SCSS locally and commit it to my git repository.

Since git is so good allowing you to hook into different phases of the commit process, all I needed was to build a pre-commit script to build and commit the CSS. But I had a couple of requirements.

  1. I only wanted the compile process to run only when changes to the SCSS are going to be commited.
  2. Sometimes I will do a number of changes and commit the changes over a couple of commits. So any CSS has to match the changes to the SCSS that I make.
  3. When I do development I compile the SCSS in development mode and use FireSASS which creates extremely verbose CSS, which is great for development, but hopeless for production. so it needs to recompile everything in production mode.

So we will start with the last issue. Compiling from the command line is easy.

compass compile --force

this will recompile all your SCSS correctly, but it will just recompile everything as your settings in the config.rb file. So with a minor change to your config.rb (see #2049245 for the patch to Zen.

# Default to development if environment is not set.
saved = environment
if (environment.nil?)
  environment = :development
else
  environment = saved
end

now I can use the following command. Basically this checks to see if the -e option is set and if not sets it to development.

compass compile -e production --force

So now all the CSS will be compiled down to as small as it can. things like using colours like #000000 will be changed to #000, so it will take a little space as possible,

Now the changes to the pre-commit hook. Since I only want to compile if I have changed SCSS I need to find the SCSS that has changed, and have been staged in git. The following will check this out for me.

git diff --cached --exit-code $theme_dir/sass/*.scss > /dev/null

This command will set an exit code equal to 1 when any of this has changed. Also since I want this to work with any site, I can start off with the following

#!/bin/sh

themes_altered=()
 
for config in docroot/sites/*/themes/*/config.rb
do
  theme_dir=`dirname $config`
 
  git diff --cached --exit-code $theme_dir/sass/*.scss > /dev/null
  if [ "$?" -eq 1 ]; then
    themes_altered+=($theme_dir)
 
    # the css is going to be blown away anyway so lets revert it to HEAD
    git checkout HEAD -- $theme_dir/css
  fi
done

Basically what this will do, loop around every theme with a config.rb, check for any staged SCSS changes and then revert the CSS back to the current HEAD (the last commit), and add it to the array of themes changed.

So now we have a list of themes with SCSS changes that have been staged to be commited.

Next I sometimes commit changes over a couple of commits. So there maybe changes I do not have staged which I need to get out of the way before I compile. So basically any changes I have not staged I want to stash.

git stash save --keep-index "Compass recompile"

Now this will stash any changes which have not been staged. Next I compile the SCSS and add this to be commited.

if [ "${#themes_altered[@]}" -gt "0" ]; then
  git stash save --keep-index "Compass recompile"
 
  for dir in "${themes_altered[@]}"
  do
    /usr/bin/compass compile $dir -e production --boring --force
 
    git add $dir/css/*.css $dir/css/*/*.css
  done
 
  git stash pop
fi

So this last part will loop thougth the list of changed themes and recompile the SCSS and add it ready to be commited, and lastly all the stashed changed will be written back down.

This has been working very well for quite a while. however I have found a couple of minor issues.

Like most people while they are developing, they will have the following command running.

compass watch

Which will watch your SCSS and compile it when ever there are changes. However if you commit parts of a file, and there is a stash done, it will try to recompile the SCSS, then you will get 1 of 2 problems. Either you will commit the development version of the CSS, or there will be problems with the SCSS when you pop the changes from the stash. So generally I just kill the watch process before I start commiting.

See the Gist Below to get the full script

#!/bin/sh

themes_altered=()

for config in docroot/sites/*/themes/*/config.rb
do
  theme_dir=`dirname $config`

  git diff --cached --exit-code $theme_dir/sass/*.scss > /dev/null
  if [ "$?" -eq 1 ]; then
    themes_altered+=($theme_dir)
    
    # the css is going to be blown away anyway so lets revert it to HEAD
    git checkout HEAD -- $theme_dir/css
  fi
done


if [ "${#themes_altered[@]}" -gt "0" ]; then
  git stash save --keep-index "Compass recompile"

  for dir in "${themes_altered[@]}"
  do
    /usr/bin/compass compile $dir -e production --boring --force

    git add $dir/css/*.css $dir/css/*/*.css
  done

  git stash pop
fi

my projects: 

Tags: 

Comments