h4ck3r+=boi v 2.0

  1. Search
  2. About
  3. Subscribe
  4. Archive
  5. Random

h4ck3r+=boi v 2.0

Newer
Older
  • SASS variables and the Rails 3.1 Asset Pipeline

    I’ve been playing with Rails 3.1 lately, and ran across a leaky abstraction in the way the new Asset Pipeline handles SASS, variables and mixins in particular.

    In my project I wanted to create a SASS file with global settings. For example:

    $tip_background_color: #AFFFCB; $border_style: thin black solid; $shaded_background: gray;

    These SASS variables I could then reference from other .scss files in my asset pipeline.

    This seems like a perfect use of SASS variables in Rails 3.1, right? Set up a theme file that declares how colors should look in the app, then use those SASS variables from other SASS files.

    Except it doesn’t work like that. Ryan Batt’s mentions this at the end of Railscast #268:

    This error is caused by the way that Sprockets work in Rails 3.1. Variables aren’t shared between SASS files

    The normal way you set up the Asset Pipeline to include your SASS files is this:

    /* * app/assets/stylesheets/application.css.scss * *= require_self *= require_true . *= require_tree ./shared_css */

    The Asset Pipeline will look at each file in app/assets/stylesheets/ and call the SASS renderer on each file individually.

    With this approach each SASS file is compiled individually, without knowing about any other file in the folder structure.

    Except, we want to have a SASS file with some global settings.

    The Answer: Have SASS include everything, then render, instead of using Asset Pipeline to do this

    The Asset Pipeline makes N different SASS rendering calls, where N is the number of files in your app/assets/stylesheets/ folder. The way to use a file with global settings is to have the asset pipeline render one file, but include all the files you want via the SASS include mechanism.

    Railscast #268 mentions this solution, so it’s not new. Ryan Bates’s solution is to manually include the files in application.css.scss

    /* * app/assets/stylesheets/application.css.scss * */ @require 'saved_settings.css.scss'; @require 'products.css.scss';

    But you have to do this with every SASS file if your asset pipeline. This sucks.

    INCLUDE ALL THE THINGS FILES!!!

    There’s a simple way you can solve this problem: use .erb.

    That’s right: use ERB, and a clever function, to automatically include all the stylesheet assets.

    1. Rename application.css.scss to be application.css.scss.erb. (Whew!)
    2. Call the function below in your ERB (implementation of this function comes later):

      <%= AssetPath.sass_require( Rails.root.join('app/assets/stylesheets/'), 'shared_css' ) %> <%= AssetPath.sass_require( Rails.root.join('app/assets/stylesheets/'), 'site_css' ) %>

    3. Turn SASS caching off for development mode by adding this line to your config/environments/development.rb:

      config.sass.cache = false

      You don’t have to do anything for production, because your SASS won’t change anyway, so caching it once is OK. Turning off caching in development mode, however, will force SASS to re-render everything for every request.

      “But Ryan, OMG won’t that take time?”. No, not really. Also, SASS doesn’t very good dependency management, so changes in dependent files (like changing a value in my global settings SASS file) won’t be picked up, unless you also change app/assets/stylesheets/application.css.scss.erb. Turning the cache off avoids this problem, especially since you’re changing things all the time in development mode (and don’t want to fight a cache).

      Obviously, the old adage is true: those who don’t understand Make are forced to rewrite it, poorly.

    The implementation of sass_require

    The implementation of AssetPath.sass_require is below. I want to put it into a gem at some point, but I want to test it in wider use before doing so. (I also want to wait until Rails 3.1 is officially released)

    (see the gist)

    Conclusion

    Having SASS itself pull in all the SASS files works pretty well, allowing SASS variables to be shared between .scss files.

    There is a disadvantage: because everything is shared, there is no variable scoping. Yes, all your variables, when SASS requires the file, are global.

    This is something to watch out for, and one of the drawbacks. However, that was part of the point of the exercise, to be able to share SASS variables…

    Posted on August 17, 2011 with 1 note

    1. unimatrixzxero liked this
    2. rwilcox posted this
  • staff

Field Notes Theme. Designed by Manasto Jones. Powered by Tumblr.