0. 背景
- 一緒に開発をしているメンバーから開発時のロードが遅いという意見があり、特にデザイナーがscssを編集するときに時間がかかるという報告がありました。私はエンジニアですので、ほとんどscssを触る機会はないのですが、開発環境が遅いと、ユーザーに素早く価値を提供できないという判断もあり、開発環境の高速化の一環として、sassc-railsの導入を試みました。
- sassc-railsは、sassのc++実装のgemであり、コンパイルがsass-railsよりも速いと言われているものです。前職の技術基盤の方に紹介してもらい、その他に有効な手立ても思い浮かばないことから、sassc-railsの導入に踏み切りました。
- このRailsアプリケーションのディレクトリ構成としては、app/assets配下にscssやjsが置かれるという、一般的なRailsのディレクトリ構成です。(多分)
1. 問題点
1-1. compass-railsを取り除く
- compass-railsはsass-rails(ruby実装)に強く依存しているため、取り除く必要があります。
1-2. spriteを取り除く
- sassc-railsでは、compassが提供するmagic importはサポートしていません。例えば、
@import 'hoge/*.png';
@include hoge-sprites;
のようなものがあると、うまく動いてくれません。
1-3. 宣言されてないプレースホルダーセレクタなどがあるとコンパイルが通らない。
-
rake assets:precompile
をするとこのようなエラーが出ます。
SassC::SyntaxError: Error: ".e__hoge_hoge .hogeSet + ul" failed to @extend "%hoge_fuga".
The selector "%hoge_fuga" was not found.
Use "@extend %hoge_fuga !optional" if the extend should be able to fail.
on line 574 of app/assets/stylesheets/_hoge_hoge.scss
>> @extend %hoge_fuga;
------------^
1-4. inline-image
が使えない。
- compassの機能であるデータURIスキーム(Base64化)のための
inline-image
はsassc-railsでは使えなさそうです。
2. 解決法(私の場合)
2-1. compass-mixinの導入
- compass-railsをGemfileから削除しました。また、sassc-railsでsassのコンパイルを高速化にあるようにcompass-mixinsを導入します。
- compassをimportしている箇所のpathを変更します。外部ライブラリを職人の手によって配置するのは好ましくありませんが、先に進めるためにまずは適当な場所に置いておきます。1
- @import 'compass';
+ @import 'path/to/compass-mixins/lib/compass';
comixins gemを使う場合は、Gemfile
にgem 'comixins'
を追加し、bundle install
したあと、
- @import 'compass';
+ @import 'comixins';
とします。
2-2. spriteの廃止
- compassのmagic import(正式名称はなんというのだろう・・・。あるいはcustom function?)については、この辺りで議論されています。
- あまり深追いはしませんでしたが、上記の問題があるので、compassのspriteを使っているところは、デザイナーさんとも話し合い、もともと廃止する予定であるということもあり、この際廃止することになりました。
- 実際の作業は、デザイナーの方が親和性が高いということと私の他タスクとの兼ね合いもあり、同僚のイケメンデザイナーに作業してもらいました。
- 幸い、spriteを使っているところはlegacyな箇所で、scss丸ごと削除できる箇所もあるなど、scssの整理も兼ねて行いました。
2-3. 宣言されてないプレースホルダーセレクタに!optional
をつける
- エラーメッセージにもあるように、
!optional
をつけておけば、定義されてない場合でもコンパイルで落ちることはありません。 - そもそも、sass-railsで
assets:precompile
を走らせた場合でも、(バージョンにもよると思いますが)WARNINGが出てくると思いますので、日々きちんと対処していれば大丈夫なはずです。(往往にしてなおざりにされますが) - 念のため、使われている箇所も確認し、今回は
!optional
をつけることで対応しました。
2-4. inline-imageの置換
- inline-imageは画像をBase64化してくれる機能です。このRailsアプリケーションでは諸々の事情により、一部の画像がBase64化されています。
- sassc-railsを導入することにより、inline-imageが使えなくなるので、他のものに代替する必要があります。
- 幸い、sassc-railsにもsass-railsと同様にasset-data-urlを使えばBase64化することができ、一斉置換することで対応できました。
grep -lr 'inline-image' app/assets/stylesheets/* | xargs sed -i.bak -e 's/inline-image/asset-data-url/g'
- background-image:inline-image('hoge.png');
+ background-image:asset-data-url('hoge.png');
速度比較
- ざっくりですが、assets:precompileの速度は以下のように変化しました。(cacheはすべて削除してから測定)
sass-rails: 24:31
sassc-rails: 1:57
- ちょっと早くなりすぎのような・・・。
最後に
- 今回の方法はあくまで私が試した方法ですので、もっと良い方法があるかもしれません。その際は優しくご教授いただけますと幸いです。
- Rails5.1からはwebpackも導入されるということで、Javascriptのエコシステムを利用できるようになればこのような問題から解放されるようになると思います。しかし、legacyなシステムは依然として存在すると思いますので、scssのコンパイルを早くしたいという方の参考になれば幸いです。
参考
- sassc-rails
- compass-mixins
- sassc-railsでsassのコンパイルを高速化
- #CookpadTechConf 2016で「Railsアプリ開発環境の高速化」について話した