SCSS precompilation: variable undefined (Rails 4)
Scenario
In /products.css.scss :
@import 'partials/colors';
@import 'partials/boxes';
#wrapper {}
In /partials/_colors.css.scss :
$light-gray: #ccc;
In /partials/_boxes.css.scss :
#box-light-gray {
background-color: $light-gray;
width: 50px;
height: 50px;
}
Problem
This happens in rake assets:precompile
, in the environment production
:
Sass :: SyntaxError: Variable Undefined: "$ light-gray". (in / partials / _boxes.css.scss: 2)
My thoughts
The file /partials/_boxes.css.scss does not have a variable $light-gray
by itself - and here I have to agree with rake assets:precompile
. The point is this: how to make it rake
recognize the injection $light-gray
in /partials/_boxes.css.scss ?
I think it rake
doesn't match the puzzle points because it doesn't know how SCSS works. I feel like I am missing something SCSS related to pair with rake
.
source to share
This is a tricky issue with the current version of Sprockets and sass-rails. You might think that the lines *= require
in your file application.css
would load the variables in order so that they are available across all scss files, but they are not. Here's what the Rails Guide pipeline says about it :
If you want to use multiple Sass files, you should generally use Sass @import instead of these Sprockets directives. With the Sprockets Directive, all Sass files exist within their own scope, variables or mixins are only available in the document they were defined in. You can also do file aliasing using @import ", and @import" * / * "to add an entire tree equivalent to how require_tree works. See the sass-rails documentation and important caveats for more information.
In other words, you have two options:
-
@import
your variables in each file as needed. - Use
@import
in your fileapplication.css.scss
instead*= require
If you go to the first option, just skip @import 'partials/colors';
to the beginning _boxes.css.scss
.
In the second option, you just need @import
your stylesheets application.css.scss
one time (in the correct order), then your variables in mixins will be available to all stylesheets. You are still using the asset pipeline here, so the precompilation will still work fine, but you allow the sass-rails
sasa magic to work. Yours application.css.scss
will look something like this:
@import 'partials/colors';
@import 'partials/*';
@import '*';
Be warned that there is currently a bug in sass-rails. If you have stylesheets .erb
, sass-rails will not be able to import them from a template if they are in a separate folder.
source to share
Without changing your scss I think your best option is to place @import 'partials/colors';
in your file _boxes.css.scss
. The biggest drawback @import
is that it contains an additional HTTP request, however, since you are precompiling your parsing, I'm not entirely sure if this is still a problem.
Possible refactoring option:
_colors.css.scss
$light-gray: #ccc;
_box-sizes.css.scss
.small-box{
width: 50px;
height: 50px;
}
products.css.scss
@import 'partials/colors';
@import 'partials/box-sizes';
.small-light-grey-box{
@extend .small-box
background-color: $light-gray;
}
Again, this is just an example. There are many ways to refactor your scss and html to get the desired result.
source to share