compassが遅い件 vol.1

0 件のコメント
以前、compassのコンパイルが遅い…と記載しましたが、
「遅い」に対していくつか対策したのでその手法を記事にしました。
(色々手法があるので、今回はvol. 1として書きます!

はじめに

compassはRubyで書かれており、モンキーパッチングが出来る。

ということで、compassのconfigファイル(config.rb)でcompassの処理を上書きすることができます。

今回は、どうやって変更を加えるのかを実験した後に
「コンパイルする対象を正規表現で絞り込むカスタマイズ」をしたいと思います。

実質的にコンパイル速度が早くなるという修正ではないです。
任意のグループでコンパイルを走らせることができるようになりました。ぐらいの変更です。
(これだけでも筆者の案件状況ではかなり効果的でした。詳しくは書かないですが、同一ソースで複数サービスが動くという状況。

最終的には、このグループでのコンパイルをforkさせ、複数のグループを並列にコンパイルさせるとこまでやりました。
今回は、それをするための前準備になります。

・compassのソースはこちら(GitHub)
https://github.com/Compass/compass

・macだと、このあたりにソースがあります
/Library/Ruby/Gems/1.8/gems/compass-0.12.2/

・筆者のcompassのバージョン
$ compass -v
Compass 0.12.2 (Alnilam)

実験する環境をつくる

まずはじめに、コンパイルできる環境を作ります。

1. コンパイル環境をつくる
任意のディレクトリに移動し、下記コマンドを実行すると、コンパイルに必要なファイル/フォルダが生成されます。
$ compass init
↓が生成される。
config.rb
sass
stylesheets

2. とりあえずコンパイルしてみる
$ compass compile --time
⇒ すると、コンパイルが走っていることが確認できます。
※ --timeオプションでコンパイルにかかった時間が表示されるので、今回は毎回このオプションをつけて実行する

実験する

compassのconfigファイル(config.rb)でcompassの処理を上書きすることができると記述しましたが、
本当に上書きできてるの?ってことを実験したいと思います。

compassでコンパイルする対象を取得するメソッドはこのような実装

config.rbに対して下記のような修正を加える(筆者はconfig.rbの下部に書いている)
module ::Compass
class Compiler
# 元のソース
def sass_files(options = {})
p "here!!"
exclude_partials = options.fetch(:exclude_partials, true)
@sass_files = self.options[:sass_files] || Dir.glob(separate("#{from}/**/#{'[^_]' if exclude_partials}*.s[ac]ss"))
end
end
end
view raw compass1.rb hosted with ❤ by GitHub

⇒ この処理は、既存のメソッドをそのままコピーし、間に「p "here!!"」と1行追加しました。
※ 上書きすることができているならば、「compass compile」時に、「here!!」とログが流れ、正常にコンパイルが通っているはず。

$ compass compile --time
"here!"
"here!"
   remove .sass-cache/
   remove stylesheets/ie.css
   remove stylesheets/print.css
   remove stylesheets/screen.css
"here!"
   create stylesheets/ie.css (0.002s)
   create stylesheets/print.css (0.001s)
   create stylesheets/screen.css (0.104s)
Compilation took 0.141s

うん、正しい!

コンパイルする対象を正規表現で絞り込むカスタマイズ

では、上記のことを利用して、コンパイル対象を正規表現で絞り込むカスタマイズをしたいと思います。

config.rbに対して下記のような修正を加える。
### コンパイル対象を絞り込みするオプション
# 指定がない場合のコンパイル対象
DEFAULT_TARGET_PATTERN = "IE"
# 値にマッチするscssファイルをコンパイル対象として絞り込む
SASS_FILE_PATTERNS = {
"IE" => "^.*ie.*$",
"PRINT" => "^.*print.*$",
}
TARGET_PATTERN = DEFAULT_TARGET_PATTERN
### コンパイル対象を絞り込む対応
module ::Compass
class Compiler
def sass_files(options = {})
exclude_partials = options.fetch(:exclude_partials, true)
opt_sass_files = self.options[:sass_files]
# ファイル指定あり
if opt_sass_files
return opt_sass_files
end
# ファイル指定なし
sass_files = Dir.glob(separate("#{from}/**/#{'[^_]' if exclude_partials}*.s[ac]ss"))
##### 取得したsass_filesを操作することで、コンパイル対象を変更することができる
target_pattern = SASS_FILE_PATTERNS[TARGET_PATTERN]
# 指定がないので絞り込ままい
if target_pattern.nil? || target_pattern.empty?
return sass_files
end
# 指定があるので正規表現で絞り込み
target_regexp = Regexp.new(target_pattern)
_sass_files = []
sass_files.each do |file|
_file = File.basename(file)
if target_regexp =~ _file
_sass_files.push(file)
end
end
return _sass_files
#####
end
end
end
view raw compass2.rb hosted with ❤ by GitHub

これは何の修正なのか?
sassファイル名が「^.*ie.*$」にマッチするファイルをコンパイルするように修正しています。
(SASS_FILE_PATTERNSのIEを指定しているためです。

コンパイルしてみる
$ compass compile --time
   remove .sass-cache/
   remove stylesheets/ie.css
   create stylesheets/ie.css (0.002s)
Compilation took 0.003s

絞り込めてる!正しい!

ちなみに、DEFAULT_TARGET_PATTERNを「PRINT」にすることで、下記のみコンパイルされることも確認。
stylesheets/print.css

コンパイル対象を変える際に、いちいちconfig.rbを書き換えるのも面倒くさい…

きっと、↑のようなことになると思うので、オプションで指定したいですよね。

config.rbでオプション追加できるかなーと思って処理を追ってみましたが、
config.rbを読み込む前にcompassコマンドのオプション解析を済ませておりました‥
(compassのcオプションでconfig.rbを指定できるので、今思うと当たり前。
http://kanapple.net/study/archives/16

ということで、コマンドをラップするしかありません。
compassをrequireしてコマンドを新たに作ろうかなーとも思ったので、面倒なので↓にしてみました。

$ mkdir bin
$ touch bin/zoocompass
$ chmod 755 bin/zoocompass
$ vim bin/zoocompass
#!/usr/bin/ruby
command_options = ARGV
# config.rbに渡すパラメータを定義
# 'key' => { // zoocompassで処理を分岐する場合に使うキー(今回は必要ないけど
# 'env' => '', // config.rbで使う環境変数名
# 'opt' => '', // zoocompass実行時に指定するオプション名
# }
#
custom_options = {
'compile_target' => {
'env' => 'TARGET_PATTERN',
'opt' => '--target',
}
}
# custom_optionsのオプションを指定していた場合は、オプションから削除+環境変数へセットする
custom_options.each do |o,v|
index = command_options.index(v['opt'])
if !index.nil?
# 環境変数へセット
option = command_options.values_at(index + 1)[0]
ENV[v['env']] = option
# オプションから削除
command_options.delete_at(index + 1)
command_options.delete_at(index)
end
end
# compassを実行する
compass_options = command_options.join(' ')
compass_command = 'compass ' + compass_options
system(compass_command)
view raw compass3.rb hosted with ❤ by GitHub

合わせて、config.rbのTARGET_PATTERN部分を下記に修正する(ENVでパラメータを受け取る
TARGET_PATTERN = ENV['TARGET_PATTERN'] || DEFAULT_TARGET_PATTERN
view raw compass4.rb hosted with ❤ by GitHub

compassをラップした「bin/zoocompass」を使うと、オプションで指定したパラメータをconfig.rbで参照できるようになります。
(それ以外はcompassと何も変わりません。

何も変わってないか、試してみる
$ ./bin/zoocompass compile --time
   remove .sass-cache/
   remove stylesheets/ie.css
   create stylesheets/ie.css (0.003s)
Compilation took 0.005s

うん、変わってない。


追加したオプションで試してみる
$ ./bin/zoocompass compile --time --target IE
unchanged sass/ie.scss
Compilation took 0.001s

うん、よい。

$ ./bin/zoocompass compile --time --target PRINT
   remove .sass-cache/
   remove stylesheets/print.css
   create stylesheets/print.css (0.003s)
Compilation took 0.004s

うん、指定できてるぽい。

できた!!

注意事項!

compassのバージョンを上げる場合は、元のソース(compass側のソース)に変更がないか要確認。
案件内でやる場合には、みんなに周知しないと。

終わりに

次回以降、これを使って並列実行させた記事も書いていきたいと思います。
やったことを少しずつ記事にしてきますー。

以上!

0 件のコメント :

コメントを投稿