Yii 2 で Twitter の Bootstrap を Less る

## はじめに
Yii 2 では yiisoft/yii2-app-basic で新しいプロジェクトを作成すると同時に yiisoft/yii2-bootstrap もインストールされ、諸々の初期設定を経て、はじめから Twitter の Bootstrap (以降 twbs と記述する) なデザインで始めることができます。

ただこのままのデザインで OK なんてことはないに等しいので、twbs はそのまま使うことにしつつ、少しデザインを変えてみたいと思います。yiisoft/yii2-bootstrap をインストールすると bower-asset 経由で twbs もインストールされるので、そのファイル群から less/bootstrap.less を引っ張ってきて Less を用いてカスタマイズしていく形を取ります。

## その前に

Yii 2 の [アセット](https://github.com/yiijan/yii2-i18n-ja/blob/master/docs/guide-ja/structure-assets.md) というドキュメントを眺めてみるとアセット変換というセクションに Less ファイルをコンパイルできそうな情報が載っているので、まずは LessAsset クラスを作成し、style.less をコンパイルしつつ、アセットを発行するやり方を試してみたいと思います。



app/less 以下に style.less を作成。

```style.less

@hoge-color: green;

.hoge {
    color: @hoge-color;
}
```

app/assets ディレクトリ以下に LessAsset クラスを作成。

```LessAsset.php
<?php

namespace app\assets;

use yii\web\AssetBundle;

class LessAsset extends AssetBundle
{
    public $sourcePath = '@app/less';

    public $css = [
        'style.less',
    ];
}
```

LessAsset クラスを読み込んでくれるように AppAsset クラスに以下を追加。

```AppAsset.php
namespace app\assets;

use yii\web\AssetBundle;

class AppAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.css',
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'app\assets\LessAsset', // 追加
    ];
}
```

最後に、ブラウザをリロード ... 。

```
Exception – yii\base\Exception

AssetConverter command 'lessc '/path/to/project/web/assets/7eea0604/style.less' '/path/to/project/basic/web/assets/7eea0604/style.css' --no-color --source-map' failed with exit code 127:
STDOUT:

STDERR:
sh: lessc: command not found
```

lessc コマンドなんてないよ？みたいなエラーが出てしまいました。よくわからないので、こういう場合はドキュメントを読むのが一番です。

> Yii はファイル名の拡張子を使って、アセットが使っている拡張構文を識別します。

とあり、

> Yii はインストールされたプリプロセッサツールに頼ってアセットを変換します。例えば、LESS を使うためには、 lessc プリプロセッサコマンドをインストールしなければなりません。

ちょっと難しいですが、要は LessAsset クラスの css プロパティで style.less と指定した場合、Yii 側で拡張子を識別して自動でコマンドを実行してくれる、みたいな感じでしょうか。

とりあえず lessc プリプロセッサコマンドというものをインストールしないといけないみたいなので npm でインストールします。(node がインストールされていると仮定)

```
npm install -g less
which lessc
```

lessc コマンドが使えるのを確認後、再度ブラウザをリロード。

見た目に変化はないですが、ソースを見ると style.css が発行されていることがわかるかと思います。app/web/assets を確認すると、style.css, style.css.map, style.less があるディレクトリも確認できるかと思います。

アセットが拡張子を識別して自動で走るコマンドについては [yii\web\AssetConverter](https://github.com/yiisoft/yii2/blob/master/framework/web/AssetConverter.php) の commands プロパティで確認することができます。

## アセットの現状

ここで問題になるのは、アセットの発行の際に *.less ファイルまで発行されることです。この問題に関しては [AssetBundle should not publish .less or .coffee files #2511](https://github.com/yiisoft/yii2/issues/2511) などで現状が確認できます。その他、Less のコンパイルに関連する情報を探しましたが、今のところベストプラクティスが見えないのが現状で *.less を発行させない場合の実装がトリッキーになる恐れもあるので Less のコンパイルは Yii のアセットに任すのはやめて、gulp というビルドツール (grunt と同じようなもの) でやることにしました。ここらへんに関しても Yii のドキュメントに記載されています。

> 上記で説明した方法の他にも、拡張構文のアセットを扱う方法はあります。例えば、grunt のようなビルドツールを使って、拡張構文のアセットをモニターし、自動的に変換することが出来ます。この場合は、元のファイルではなく、 結果として作られる CSS/JavaScript ファイルをアセットバンドルのリストに挙げなければなりません。

## gulp でやってみよう

package.json をプロジェクトルートに用意します。

```package.json
{
  "devDependencies": {
    "gulp": "latest",
    "gulp-load-plugins": "latest",
    "gulp-autoprefixer": "latest",
    "gulp-minify-css": "latest",
    "gulp-less": "latest",
  }
}
```

gulp 関連のパッケージをインストール。

```
npm install
```

gulpfile.js を作成。

```gulpfile.js
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

gulp.task('less', function() {
  gulp.src('./less/style.less')
    .pipe($.less())
    .pipe($.autoprefixer('last 2 version', 'ie 8'))
    .pipe($.minifyCss({keepBreaks: true}))
    .pipe(gulp.dest('./less/compiled'));
});
```

app/less/style.less をコンパイルして、適切にベンダープレフィックスを付与しつつ最小化し app/less/compiled 以下に置く、みたいな感じです。

less/style.less は以下のようにしました。

```style.less
@import "../vendor/bower/bootstrap/less/bootstrap.less";
@brand-success: red;
```

twbs の bootstrap.less を引っ張ってきて、とりあえず動作確認のため Yii プロジェクトのホーム画面でも使われているボタンの色を赤にしています。

LessAsset クラスも書き換えます。 

```LessAsset.php
namespace app\assets;

use yii\web\AssetBundle;

class LessAsset extends AssetBundle
{
    public $sourcePath = '@app/less/compiled';

    public $css = [
        'style.css',
    ];
}
```

Less のコンパイルは gulp に任せて、コンパイルした css ファイルをアセットに発行するようにしました。あと初期で構成されている yii\bootstrap\BootstrapAsset (twbs から CSS ファイルをインクルードするクラス) を呼ばないように config/web.php で以下のようにします。

```web.php
<?php
$config = [
    'components' => [
        ...
        'assetManager' => [
            'linkAssets' => true,
            'bundles' => [
                'yii\bootstrap\BootstrapAsset' => false,
            ],
        ],
```

最後に `gulp less` コマンドを実行して Less をコンパイルし、ブラウザをリロード。Get started with Yii ボタンが赤色になっていれば成功です。一応ソースも見て、ヘッダーにある style.css の中身も確認しておきましょう。 

## まとめ

Yii 2 を触って間もないですが、これだけでもけっこう苦労しました。現状では Less のコンパイルは Yii 側では任せないほうが無難なのかなと思うんですが、どうなんでしょう？もっと簡単でエレガントな方法があれば教えてください！

## 関連リンク

- [Yii 2 ガイド: アセット](https://github.com/yiijan/yii2-i18n-ja/blob/master/docs/guide-ja/structure-assets.md)
- [Yii2の削除確認ダイアログをかっこ良くする](http://qiita.com/tanakahisateru/items/be28b7bed4566ce8fa99)
- [Qiita: Yii 2.0.0 で独自のアセットクラスを作成するときの注意点
](http://qiita.com/livejam_db/items/71c5c24134f6b71d40c1)