gulp + decomposer: Best way to sassy-@import bower components

gulp + Browserify(+ debowerify)という構成で Web サイトを作っていると、SASS にも debowerify 相当のものが欲しくなってくる。

ちなみに、debowerify というのは、

var Velocity = require("velocity");

という JavaScript を、

var Velocity = require("./../../bower_components/velocity/velocity.js");

という風に、bower_components 内のパスに解決してくれる Browserify transform だ。 欲しいのはこれの SASS 版。

「あったらいいのにな〜」と思うようなライブラリは Github で検索すれば必ず出てくる。はずだったが、無かった。

そこで decomposer という gulp プラグインを作った。

使い方

まずはnpm install --save-dev gulp gulp-sass decomposerで必要なものをインストールしておく。既存のプロジェクトに追加するなら decomposer だけでいい。

gulpfile.js はこのように定義しておく。

var gulp = require("gulp");
var sass = require("gulp-sass");
var decomposer = require("decomposer");

gulp.task("styles", function () {
  gulp
    .src("src/styles/**/*.sass")
    .pipe(decomposer())
    .pipe(sass({ indentedSyntax: true }))
    .pipe(gulp.dest("dist/css"));
});

ポイントはsass よりも前decomposerを挟むこと。なぜなら、外部から@import した mix-ins や変数は SASS コンパイル時に解決されるからだ。sassよりも後に置くと、SASS が@import を解決出来ずにエラーが発生する。

続けて SASS を書こう。

@import normalize.sass;
@import styles/font body font-family: $ff-gothic;

$ff-gothicuetchy/stylesfont.sass で定義されている font-family だ。

最後に Bower を使って必要なアセットをインストールする。

bower i --save normalize.sass
bower i --save uetchy/styles

これで完成。後はgulp stylesを実行するだけだ。

ファイルパス解決時のポイント

decomposer は Bower モジュールに入っている任意のファイルを指定して@import することが出来る。 記法はこのようになる。

@import [Bowerモジュール名]/[ファイル名];

例えば、よく使うスタイルをまとめた uetchy/styles_font.sass を@import するなら、

@import styles/font;

と書ける。 ここでもし@import stylesと、ファイル名を省略して書くとどうなるのだろうか? コンパイルに失敗する? そんなことはない。

モジュール名だけを書くと、decomposer はbower.jsonに書かれている main ファイルを見つけ出して、それを@import してくれるのだ。

もし main ファイルが複数指定されていたら、index.sass[モジュール名].sass、またはmain っぽい名前 を持つファイルを@import する。

つまり、

@import normalize.sass;

と書けば、

@import ../bower_components/normalize.sass/normalize.sass;

という風に解決される。

まとめ

これでスタイルの@import をすっきり書けるようになった。 とはいえ、component 対応や Plain CSS のインライン展開や.less 対応など、追加したい機能は色々ある。

もし Contribution に興味があるなら、Github リポジトリをフォークしてほしい。