MojoliciousでSassを使ってみた

# MojoliciousでSassを使う
今MojoliciousでCGIゲームの三国志NETの改造版だったものをぼちぼち作りなおしているんですが、css書いている時にやっぱりSass使いたいなー、と思って色々調べてみました。
環境
Ubuntu 14.04
perl 5.22.2
Mojolicious 7.00
Mojolicious::Plugin::AssetPack 1.17
CSS::Sass 3.3.0

## どんなモジュールがあるか
早くMojoliciousでSassを使う方法を知りたい人はここは飛ばした方がいいです。

CPANやgithubを軽く調べた感じだと、MojoliciousでSassを使うには以下のモジュールが
・Mojolicious::Plugin::AssetPack
・Mojolicious::Plugin::Sass
・Mojolicious::Plugin::SassRenderer
更にPlackのモジュールが
・Plack::Middleware::File::Sass

### Mojolicious::Plugin::AssetPack
唯一今でも活発に開発＆メンテが続いているモジュールでした。
仕組みとしては CSS::Sass もしくはRubyのgemからSassをインストールしたものを使ってコンパイルしているようです。
別ファイルに記述したSassファイルをサーバー立ち上げ時にコンパイルする、といったプラグインのようです。
ちなみにこのプラグインでCoffeeScriptやlessなども使えるそうです。
### Mojolicious::Plugin::Sass
Text::Sassをつかって、テンプレートの中に記述したSassをコンパイルするプラグインのようです。
しかし別ファイルに記述したSassファイルはコンパイルしてくれませんし、何よりも Text::Sass はSassの実装がちゃんとできていないのでSassの機能のいくつかが使用できません。(import,extendが使えないなど...)
### Mojolicious::Plugin::SassRenderer
5年近く更新されていませんでした。また、これもText::Sassを使っているのでボツですね...
### Plack::Middleware::File::Sass
これも何年も更新されてなく、Text::Sassを使っていてますし、そもそも僕はPlackで立ち上げていないのでボツですね...



というわけで、各モジュールを調べた結果Mojolicious::Plugin::AssetPack一択となりました。
ですがMojolicious::Plugin::AssetPackではちょっとテンプレートの中にSassを記述したい時などには使えないようなので、テンプレートの中でSassを記述するプラグインは別途自作してしまうことにしました。

# 1.別ファイルにSassを記述するとき→Mojolicious::Plugin::AssetPackを使う

## 1.CSS::Sass、Mojolicious::Plugin::AssetPackをインストールする

`cpanm CSS::Sass`
`cpanm Mojolicious::Plugin::AssetPack`

でCSS::Sass、Mojolicious::Plugin::AssetPackをインストール。
ちなみに僕の環境ではMojolicious::Plugin::AssetPackのインストール時にテストにこけてインストールに失敗したので、--forceオプションをつけてインストールしなおしました。

## 2.基本的な使い方
※Sassファイルはプロジェクトディレクトリ内のassetsディレクトリ内に置きます。

```pl:/lib/Myapp.pm
$self->plugin('AssetPack' => {pipes => [qw/Css Sass/]});
$self->asset->process('base.css' => ('scss/base.scss'));
```

```erb:テンプレート側
%= asset 'base.css'
```
これでサーバーを立ち上げるたびに(変更があれば)別ファイルに記述したsassファイルをコンパイルし、できたcssファイルを読み込んでくれるようになります。

他にも色々できます、詳しくは[ドキュメント](http://search.cpan.org/~jhthorsen/Mojolicious-Plugin-AssetPack-0.69/lib/Mojolicious/Plugin/AssetPack.pm)を読むべし！

# 2.テンプレートの中に直接Sassを記述したい場合→CSS::Sassを使った自作プラグインで

なかなかいい感じの Mojolicious::Plugin::AssetPack ですが、テンプレートの中に直接記述したSassの面倒までは見てくれません。
他のSass関係のモジュールは未完成の Text::Sass を使用しているため満足に記述できません。
なので CSS::Sass を使って簡単にテンプレートの中のSassコードをコンパイルしてくれるプラグインを作ってみました。 
コードはこんなかんじです：

```pl:InnerSass.pm
package Mojolicious::Plugin::InnerSass {

  use Mojo::Base 'Mojolicious::Plugin'; # Mojolicious::Plugin を継承
  
  use Mojo::Cache; # キャッシュに使用
  use CSS::Sass; # Sass,Scssコンパイラ
  
  has 'sass' => sub { CSS::Sass->new( output_style => CSS::Sass::SASS_STYLE_EXPANDED() ) };
  has 'cache' => sub { Mojo::Cache->new(max_keys => 200) };

  sub register {
    my ($self, $app, $conf) = @_;

    $app->helper(sass_to_css => sub {
      my ($c, $sass, $conf) = @_;
      my $route = $c->current_route();
      my $cache = $self->cache->get($route) // '';
      if ($cache) {
        $app->log->debug('Loading sass data...');
        return $cache;
      } else {
        my $compile_sass = $self->sass->compile($sass);
        $self->cache->set($route => $compile_sass) if $conf;
        return $compile_sass;
      }
    });
  }

}
1;
```

```erb:テンプレート側
%= stylesheet begin
<% my $sass = ' # sassコードを変数に格納
  
$red:'.$config->{'color'}{'red'}.';  
  
.red {  
  color: $red;  
}  
  
'; %>
%== sass_to_css($sass, 1); #sassコードをcssに変換、キャッシュする、返却値はXMLエスケープせずに出力
%= end
```
プラグインのファイルは`/lib/Mojolicious/Plugin`に置いて、あとは Myapp.pm で読みこめばテンプレートでSass,Scssが記述できるようになります。
一度コンパイルしたものはメモリに保存しているので、初回以外は処理時間がかかるということもありません。
まあ処理時間がかなりかかるほど大きいコードなら別ファイルに分けた方がいいですし、主に開発時に使用する用のプラグインになりますが。
テンプレート側の記述もちょっと気持ち悪いですけど、個人で使う分だしこんなもんでいいかなあと。