同じ轍を踏まないためにも、人柱になった自分を供養するためにも、ここにメモしておきたいと思います。
ちなみにアホかと思いますが、この件で4~5時間くらい悩んでいました。
前提
以下の条件でCSSをコンパイルしたい要件だったので、普通に何も考えずに assets:precompile
するわけにはいきませんでした。
- Railsでassets:precompileする対象のマニフェストファイルに、
require_self
require_tree
などのディレクティブは書かない - 必要なディレクトリ・ファイルはすべて
@import
して読み込む順番を制御する -
assets/stylesheets/
以下のCSSファイルをごっそり整理するために、ファイルを削除しまくったり、一時的に空のディレクトリを用意したりしておく必要がある
TL;DR
結論を先に書くと、 @import
する対象のディレクトリ内に何もファイルを置いていない状態だと、エラーが起きてしまいます。なので、空のファイルであっても、便宜的に置いておく必要があったようです。ちなみに、 .keep
ではだめでした。ちゃんと assets:precompile
の対象となる拡張子 (.scss、.coffeeなど)じゃないとだめなようです。
mixins/
└ _buttons.scss # 中身はまだ空っぽ
variables/
└ _colors.scss # 中身はまだ空っぽ
templates/
└ users/
└ foo.scss # 中身はまだ空っぽ
└ bar.scss # 中身はまだ空っぽ
application.scss
@import "variables/*";
@import "mixins/*";
@import "templates/**/*";
なぜこういうディレクトリ構成にしたかったか
通常、Railsでアセットパイプラインを管理する場合、 assets/stylesheets/
以下に、マニフェストファイルを置いておくと思います。デフォルトだと以下のようなディレクティブの書かれたファイルがおそらくあるでしょう。
/* ...
*= require_self
*= require_tree .
*/
ただこの場合だと、呼び出すファイルの順番をコントロールできないようです。
2.4 マニフェストファイルとディレクティブ | Rails Guide アセットパイプライン
ディレクティブは記載した順に実行されますが、require_treeでインクルードされるファイルの読み込み順序は指定できません。従って、特定の読み込み順に依存しないようにする必要があります。
たとえば共通で使っている変数なんかもいちいち各ファイルで呼び出さないといけなかったりします。うーんこれはDRYじゃない。
@import "../variables/*";
.foo {
/* some styles */
}
@import "../variables/*";
.foo {
/* some styles */
}
そこで、マニフェストファイル内ですべて @import
しちゃえ!と思って、requireなんとかをやめてみたというわけです。そしたら、冒頭のようなディレクトリ構成でも、各ファイルで @import
する必要もなくなるでしょう。
はたして、この構成が効率良いのかはまだ検証の余地があると思いますが、コントロールできる範囲が明確になって良き…といった感じです。