読者です 読者をやめる 読者になる 読者になる

yutaponのブログ

javascript界隈の興味あるネタを備忘録的に残しておく場所

gulpでsassをコンパイルするタスクを作る

何番煎じかわからないけど、gulpを使ってみたら中々良かったのでまとめてみます。

gulp.jsとは

f:id:sskyu:20140910195209p:plain

gulp.js はフロントエンド用のタスクランナーってやつです。

同じタスクランナーの競合に Grunt がありますが、後発だけあってストリームを駆使して可読性の良い設定ファイルが書けます。

Gruntでできることは大体gulpでもできるので、どちらを使ったら良いかは好みの問題かも知れません。

この記事ではsassのコンパイルをするタスクと、関連してベンダープレフィックスを自動で付与するところまで紹介します。

gulpのインストール

npmコマンドでサクッと入れます。

 $ npm install -g gulp

これでgulpコマンドが使えるようになりました。

gulpでsassのコンパイルをする

gulpでsassをコンパイルするのに、こちらのプラグインを使います。

gulp-ruby-sass - Compile Sass to CSS with Ruby Sass

よく読むと、rubyとsassが使えるようになっていないといけません。

下準備

rubyは使えるとして、もしsassが入っていなければgem installします。 (ちなみに私はrbenvでrubyをインストールしています)

$ gem install sass
Fetching: sass-3.4.3.gem (100%)
Successfully installed sass-3.4.3
Parsing documentation for sass-3.4.3
Installing ri documentation for sass-3.4.3
Done installing documentation for sass after 8 seconds
1 gem installed
# (↑既にsassが入ってる状態でinstallした結果)

$ rbenv rehash  # ←rbenvで自動で反映させるgem使ってなければやる

これで下準備が整ったのでgulp-ruby-sassを入れます。

$ npm install --save-dev gulp-ruby-sass

それではgulpのタスクを作っていきます。

gulpfile.jsにタスクを作る

プロジェクトルート直下にgulpfile.jsを作成して、中身はこんな感じにします。

// @file gulpfile.js

var gulp = require('gulp');
var sass = require('gulp-ruby-sass');

// $ gulp sass で実行するタスク
gulp.task('sass', function () {
  gulp.src('sass/**/*.scss')
    .pipe(sass({
        style : 'expanded'
    }))
    .pipe(gulp.dest('dist/css/'));
});

何をやっているかというと、gulp.src('sass/**/*.scss')sass/ディレクトリ以下の.scssファイルを全てコンパイルの対象にしています。

sass({ style : 'expanded' })では対象になったファイルを実際にコンパイルしています。

gulp.dest('dist/css/')ではコンパイルされたcssファイルをdist/css/以下に、元々あったディレクトリ構成のまま配置しています。

この例は一番簡単な例なので、もう少し見ていきます。

watchタスクを作る

scssファイルに変更があったら自動的にコンパイルしてほしいものです。

そういうときはwatchタスクを作ります。

// @file gulpfile.js
var gulp = require('gulp');
var sass = require('gulp-ruby-sass');

gulp.task('sass', function() {
  gulp.src('sass/**/*.scss')
    .pipe(sass({
        style : 'expanded',
    }))
    .pipe(gulp.dest('dist/css/'));
});

// 追記する
gulp.task('watch', function () {
    gulp.watch('sass/**/*.scss', ['sass']);
});

gulp.watch()の第一引数にはgulp.src()の第一引数と同じ書き方で指定します。(配列でも指定できます)

第二引数には変更を検出した際に実行するタスク名を配列で指定します。

watchタスクができたので$ gulp watchでwatchを開始します。

$ gulp watch
[gulp] Using gulpfile ~/hoge/fuga/gulpfile.js
[gulp] Starting 'watch'...
[gulp] Finished 'watch' after 7.05 ms

これでscssファイルを編集する度にsassのコンパイルが走るようになりました。

しかし、watch中にsassのコンパイルエラーが発生(シンタックスエラーなど)するとwatchが解除されてしまいます。

これを防止するために gulp-plumber を入れます。

$ npm install --save-dev gulp-plumber

次にsassタスクを少し修正します。

// @file gulpfile.js
var gulp    = require('gulp');
var sass    = require('gulp-ruby-sass');
var plumber = require('gulp-plumber'); // 追記

gulp.task('sass', function() {
  gulp.src('sass/**/*.scss')
    .pipe(plumber) // 追記
    .pipe(sass({
        style : 'expanded'
    }))
    .pipe(gulp.dest('dist/css/'));
});

gulp.task('watch', function () {
    gulp.watch('sass/**/*.scss', ['sass']);
});

これでwatch中にエラーが発生しても中断されなくなりました。

autoprefixerを使ってベンダープレフィックスを自動で付ける

ベンダープレフィックスはゆくゆくは外れていくものなので、このブラウザはベンダープレフィックスが必要というような知識はすぐに要らなくなってしまいます。

こういうことは人間が覚えるのではなく、コンピュータに自動でやってもらいましょう。

ということで、autoprefixerを使ってベンダープレフィックスを自動でつけてもらいます。

autoprefixerの仕組ですが、Can I use を見てベンダープレフィックスが必要かどうかチェックしているようです。

ブラウザのバージョン指定もできて便利なので使っておくことを勧めます。

ちょっと調べると gulp-autoprefixer よりも gulp-pleeease の方がおすすめされてるようです。

タスクを細かく分割したいなら gulp-autoprefixer 使えばいいですし、まるっとminifyまでやって欲しいなら gulp-pleeease使えばいいような気がします。

参考:gulp-autoprefixerよりもいい感じ。gulp-pleeeaseを使ってcssを処理しよう

ということで、gulp-pleeeaseをインストールします。

$ npm install --save-dev gulp-pleeease

gulpfile.jsに追記します。

// @file gulpfile.js
var gulp     = require('gulp');
var sass     = require('gulp-ruby-sass');
var plumber  = require('gulp-plumber');
var pleeease = require('gulp-pleeease'); // 追記

gulp.task('sass', function() {
  gulp.src('sass/**/*.scss')
    .pipe(plumber())
    .pipe(sass({
        style: 'expanded'
    }))
    .pipe(pleeease({ // 追記
        autoprefixer: {
            browsers: ['last 2 versions']
        },
        minifier: false // minify無効
    }))
    .pipe(gulp.dest('dist/css/'));
});

gulp.task('watch', function () {
    gulp.watch('sass/**/*.scss', ['sass']);
});

gulp-pleeeaseに指定できるオプションについてはこちらのドキュメントに書いてます。

それではどんな感じにベンダープレフィックスを付けてくれるのか見てみます。

display: flex

display: flexほどベンダープレフィックス覚えるのが大変なものはないのではないでしょうか。

ということで、ためしに上下中央寄せにするsassをコンパイルしてみます。

.centerMiddle {
    display: flex;
    justify-content: center;
    align-items: center;
}

出力されたcssファイルはこのようになりました。

.centerMiddle {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
  -webkit-align-items: center;
      -ms-flex-align: center;
          align-items: center;
}

今回は出力を見やすくするためにminifier: falseを指定しましたが、デフォルトでminifiler: { preserveHacks: true, removeAllComments: true }が効いているので、出力をきれいに見たいとき以外は指定しないほうがいいです。

Compassを使っている場合

もしsass+compassを使っている場合、compass側で用意されているscssを読み込もうとしてエラーになる場合があります。

# ↓こんなエラー
Plumber found unhandled error: Error in plugin 'gulp-ruby-sass'
Message:
    error hoge.scss (Line 2: File to import not found or unreadable: html5reset.

こういう時はsass()の部分を次のようにするとエラーを回避できます。

        .pipe(sass({
            style   : 'expanded',
            compass : true // ←これ付けるだけ
        }))

それでも以下のようなエラーが出る場合がありますが

gulp-ruby-sass: ERROR: Cannot load compass.

この場合はcompassが原因なので、

$ gem install compass --pre

新しいバージョンのcompassを入れ直すとよいようです。

おわりに

gulpのタスクは上から下へ処理が流れるので読みやすいですね。

gulpはストリームをベースにしているということで、フロー制御がGruntよりもわかりにくい印象あるんですが、慣れればだいぶ親しみわきます。

今回sassのコンパイルの話だけだったので、gulpはもう一回くらいやってみるかも。