compassが遅い件 vol.3
「compassが遅い件 vol.2」の続きです。今回はcssの生成を並列化したいと思います。
ディレクトリ構成等々は、vol.1・vol.2と同様です。
またもやconfig.rbに処理を書き込むカタチになります。
※ vol.1に記載した↓とは別件です。
> 最終的には、このグループでのコンパイルをforkさせ、複数のグループを並列にコンパイルさせるとこまでやりました。
> 今回は、それをするための前準備になります。
必要なものをインストールする
今回は並列実行ということで、Parallelというgemを使いたいと思います。
(スレッド数の管理もしてくれるし、とても楽に導入できたので。)
・Parallelをインストール(筆者はMacです…)
$ sudo gem install parallel
・Compassのバージョン
$ compass -v
Compass 0.12.2 (Alnilam)
Copyright (c) 2008-2014 Chris Eppstein
Released under the MIT License.
Compass is charityware.
Please make a tax deductable donation for a worthy cause: http://umdf.org/compass
並列化が実感できる環境をつくる
「vol.2」で作成したsass/test.scssはコンパイルに10秒以上かかっていたので、test2.scssとtest3.scssをつくり、css生成がブロックされる状態にしておく。
$ cp -ip sass/print.scss sass/test2.scss
$ cp -ip sass/print.scss sass/test3.scss
準備オッケー。
通常のコンパイルをしてみる。
$ compass compile --time --force
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.03s)
identical stylesheets/test.css (18.165s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.0s)
Compilation took 18.201s
test.css生成に時間がかかり、test2.cssとtest3.cssの生成がブロックされているのが分かります。
ソースの修正
修正箇所は、sass_filesのループで回してるところをparallelを使って並列化させるだけ。
ここの処理を_config.rbで上書きし、並列化させる。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'parallel' | |
module ::Compass | |
class Compiler | |
def run | |
failure_count = 0 | |
if new_config? | |
# Wipe out the cache and force compilation if the configuration has changed. | |
remove options[:cache_location] if options[:cache_location] | |
options[:force] = true | |
end | |
# Make sure the target directories exist | |
target_directories.each {|dir| directory dir} | |
# Compile each sass file. | |
result = timed do | |
Parallel.each(sass_files.zip(css_files), :in_threads => 2) do |sass_filename, css_filename| | |
begin | |
compile_if_required sass_filename, css_filename | |
rescue Sass::SyntaxError => e | |
failure_count += 1 | |
handle_exception(sass_filename, css_filename, e) | |
end | |
end | |
end | |
if options[:time] | |
puts "Compilation took #{(result.__duration * 1000).round / 1000.0}s" | |
end | |
return failure_count | |
end | |
end | |
end |
すると、上限2スレッドでcss生成が開始される。
(test.cssでブロック中にtest2.css、test3.cssが生成されてるのがわかる。
(test.cssでブロック中にtest2.css、test3.cssが生成されてるのがわかる。
$ compass compile --time --force
identical stylesheets/ie.css (0.001s)
identical stylesheets/print.css (0.001s)
identical stylesheets/screen.css (0.016s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.001s)
identical stylesheets/test.css (16.213s)
Compilation took 16.216s
オプションで指定できるようにする
例のごとく、環境変数でパラメータを受け取れるようにします。今回は、全ソース乗っけます。(いろいろ細かく書いていってたので、まとめの意味で。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### コンパイル対象を絞り込みするオプション | |
# 指定がない場合のコンパイル対象 | |
DEFAULT_TARGET_PATTERN = "" | |
# 値にマッチするscssファイルをコンパイル対象として絞り込む | |
SASS_FILE_PATTERNS = { | |
"IE" => "^.*ie.*$", | |
"PRINT" => "^.*print.*$", | |
} | |
TARGET_PATTERN = ENV['TARGET_PATTERN'] || DEFAULT_TARGET_PATTERN | |
# 画像生成のサイズをメモリにキャッシュさせる | |
DEFAULT_DIMENSIONS_CACHE = false | |
if ENV['DIMENSIONS_CACHE'] === "true" | |
DIMENSIONS_CACHE = true | |
elsif ENV['DIMENSIONS_CACHE'] === "false" | |
DIMENSIONS_CACHE = false | |
else | |
DIMENSIONS_CACHE = DEFAULT_DIMENSIONS_CACHE | |
end | |
# cssファイル生成のスレッド数 | |
MAX_COMPILE_THREADS = 2 #上限値(超えたら並列生成しない | |
DEFAULT_COMPILE_THREADS = 1 | |
COMPILE_THREADS = ENV['COMPILE_THREADS'] && ENV['COMPILE_THREADS'].to_i || DEFAULT_COMPILE_THREADS | |
### コンパイル対象を絞り込む対応 | |
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 | |
### image-width/image-heightの高速化 | |
if DIMENSIONS_CACHE | |
module ::Compass::SassExtensions::Functions::ImageSize | |
@@dimensions_cached = {} | |
def image_dimensions(image_file) | |
if @@dimensions_cached[image_file.value].nil? | |
options[:compass] ||= {} | |
options[:compass][:image_dimensions] ||= {} | |
options[:compass][:image_dimensions][image_file.value] = ImageProperties.new(image_path_for_size(image_file.value)).size | |
@@dimensions_cached[image_file.value] = options[:compass][:image_dimensions][image_file.value] | |
end | |
@@dimensions_cached[image_file.value] | |
end | |
end | |
end | |
### cssファイル生成を並列化 | |
if MAX_COMPILE_THREADS >= COMPILE_THREADS && COMPILE_THREADS > 1 | |
require 'parallel' | |
module ::Compass | |
class Compiler | |
def run | |
failure_count = 0 | |
if new_config? | |
# Wipe out the cache and force compilation if the configuration has changed. | |
remove options[:cache_location] if options[:cache_location] | |
options[:force] = true | |
end | |
# Make sure the target directories exist | |
target_directories.each {|dir| directory dir} | |
# Compile each sass file. | |
result = timed do | |
Parallel.each(sass_files.zip(css_files), :in_threads => COMPILE_THREADS) do |sass_filename, css_filename| | |
begin | |
compile_if_required sass_filename, css_filename | |
rescue Sass::SyntaxError => e | |
failure_count += 1 | |
handle_exception(sass_filename, css_filename, e) | |
end | |
end | |
end | |
if options[:time] | |
puts "Compilation took #{(result.__duration * 1000).round / 1000.0}s" | |
end | |
return failure_count | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
command_options = ARGV | |
# config.rbに渡すパラメータを定義 | |
# 'key' => { // zoocompassで処理を分岐する場合に使うキー | |
# 'env' => '', // config.rbで使う環境変数名 | |
# 'opt' => '', // zoocompass実行時に指定するオプション名 | |
# } | |
# | |
custom_options = { | |
'compile_target' => { | |
'env' => 'TARGET_PATTERN', | |
'opt' => '--target', | |
}, | |
'dimensions_cache' => { | |
'env' => 'DIMENSIONS_CACHE', | |
'opt' => '--enable-dimensions', | |
}, | |
'compile_threads' => { | |
'env' => 'COMPILE_THREADS', | |
'opt' => '--compile-threads', | |
} | |
} | |
# 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) |
下記のようなコマンドで実行できます。
$ ./bin/zoocompass compile --time --force --compile-threads 2
終わりに
だいぶ複雑になってきましたね。。
苦肉の策でもあるので、ほんとにどうしようもないときに。。とか使いどきを選んでいただきたい所存。
以上!
苦肉の策でもあるので、ほんとにどうしようもないときに。。とか使いどきを選んでいただきたい所存。
以上!
登録:
コメントの投稿
(
Atom
)
0 件のコメント :
コメントを投稿