vendor prefix, minify, 開発/本番用ビルドの切り替え... CSSのあれこれをGulpにさせてみた

  • 91
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

普段業務ではタスクランナーにGruntを使っているのですが、別件で簡単なアプリケーションを作ることになりました。

小さいプロジェクトにはGruntよりGulpがいいんじゃない?とか
今流行ってるし一回使ってみるかとか

そういう気分で試してみたので、メモを兼ねて紹介します。

GruntとGulpの違い

Grunt:「設定ファイル」に近い
箇条書きのようにつらつらと設定を書いていくため、タスクの流れを読みづらく、膨大になりやすいという欠点がある。(もちろんとても便利ですが)
(今のプロジェクトではcoffeeで書いてるのに700行くらいあって泣いてる)

Gulp:処理を「プロセス」として記述
あれをこうしてここに入れる、と処理が一連のプロセスになるので、読みやすい。
あとなんか速いらしい。(曖昧)

大体このくらいの認識です。

バージョンとか

  • node: v0.10.29

下記をpackage.jsonに追加して$ npm install

package.json
"devDependencies": {
  "gulp": "3.8.9",
  "gulp-pleeease": "1.0.4",
  "gulp-ruby-sass": "0.7.1",
  "minimist": "1.1.0"
}

gulpにさせるタスク

簡単なアプリケーションなのでさっくり作りたい。楽したい。

作りながら必要そうなものを追加していったところ、vendor prefixどうしよう?と思い、

こちらの記事を見て、ああなんか良さそう〜と思いgulp-pleeeaseを使ってみました。

今回やるのは以下の2つ。

  • vendor prefixの自動付加
  • 開発時と本番時での圧縮の切り替え

(あとjsもちょっとやってるけどconcatしかまだしていないので省略)

1. vendor prefixの自動付加

vendor prefixに関する悩み

ベンダープリフィックスを付加することで、CSS3で対応予定(正式には未対応)&ブラウザで先行的に採用されている機能を使うことができます。

でも意外に早く使えるようになっているので、例えばborder-radiusとか今はほぼprefixなしでも動きます
去年入社直後に実装した時には「普通角丸にはprefixつけるよね」と教えてもらったのに…。

SCSSでせっせとprefixを書き加えたり、我流のmixinを使ってprefixをつけていましたが、それって結構無駄なんじゃ…?と、呆然としました。(border-radiusにはいらないけどdisplay: flexには必要…と、ものによって対応状況がまちまちなので、mixinからは「webkit」を消すことができない…)

というか現実問題、その頃書いた「今動いている」コードを今更直す機会なんて起こり得ない。

そんなブラウザの対応状況にいちいち、人力で対応してられません。
なら、ツールに任せちゃおう、というのが「Pleeease」。

Pleeeaseって?

Pleeease

Pleeease is a CSS post-processor. It simplifies the use of preprocessors and helps keep stylesheets as small as possible for a better maintenability.

ふんわり意訳すると

  • SASSとかstylusとかのコードを簡潔にしてくれる
  • スタイルシートをできるだけメンテナンスコストを低く運用する補助をしてくれる

まさに「運用」開発者向け。

色々機能はあるけどそれはサイトを見てもらうということで。

gulp-pleeeaseは、PleeeaseをGulpで使えるようにしたものです。

vendor prefixは「ポスト」プロセッサーでつける

Pleeeaseでは、Autoprefixserを使ってvendor prefixを付加しています。
これは、Can I use...で今必要なprefixを付加してくれる、CSSポストプロセッサー、らしい。
(SCSSはCSSにする「前に」書くものだからプリプロセッサーと言うのに対して、CSSに対して「後から」処理を行うものをポストプロセッサーと言うっぽい。たぶん。)

css
.hoge {
  display: flex;
}

と書いてAutoprefixerを通せば

css
.hoge {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}

と展開してくれる。(2014/11/10現在、last 4 versions指定時)

SCSSにせっせと書いていたprefixを、CSSに直接「必要なものだけ」書き加えてくれる。なにこれ超便利。

使い方

gulpfile.js
gulp.task('css', function() {
  return gulp.src('assets/stylesheets/app.scss')
    .pipe(sass({ style: 'expanded' }))  // CSS展開のスタイル選択
    .pipe(please({
      autoprefixer: {"browsers": ["last 4 versions", "Android 2.3"]}
    }))
    .pipe(gulp.dest('build/assets/css/'));  // 出力先
});

対応バージョンはプロジェクトに応じて・時期に応じて切り替わるので、その都度対応すべきバージョンを書き換えるだけで、prefixを全て書き換えて出力してくれる、というのが最大の魅力。

詳しくはAutoprefixer - Browsersを参照して下さい。

検証

※ 2014/11/10現在の検証です。

display: flexをCan I use...で見たとき、Android 4.4.4はSupportedになっており、Androidの2つ前のバージョン(4.3)ではprefixつきでSupportedになっていました。
最新〜4つ前までのバージョンまでを実際にビルドして出力を比較してみました。

ビルド前のソースは全て下記。

assets/stylesheets/app.scss
.hoge {
  display: flex;
}
  • バージョンを各ブラウザの3つ前まで対応させたとき
gulpfile.js(一部抜粋)
    .pipe(please({
      autoprefixer: {"browsers": ["last 4 versions"]}
    })
build/assets/css/app.css(出力)
.hoge {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}
  • バージョンを2つ前まで対応させたとき(1つ前も同じだった)
gulpfile.js(一部抜粋)
    .pipe(please({
      autoprefixer: {"browsers": ["last 2 versions"]}
    })
build/assets/css/app.css(出力)
.hoge {
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}
  • バージョンを最新のものだけ対応させたとき
gulpfile.js(一部抜粋)
    .pipe(please({
      autoprefixer: {"browsers": ["last 1 versions"]}
    })
build/assets/css/app.css(出力)
.hoge {
  display: -webkit-flex;
  display: flex;
}

ちゃんと指定バージョンごとにprefixが切り替わってますね。
Android 4.4.4ではprefixは不要ですが、Safariではprefixが必要とのことで、-webkit-がついているものと思われます。

2. 開発時と本番時での圧縮の切り替え

スマホ向けサービス開発者にとっては、ソースはなるべく小さく速く。ということで、普段のプロジェクトでは、

  • 開発時には(デバッグ用に)圧縮していないソース
  • 本番リリース時には圧縮(改行やコメントを消して1行に)したソース

を利用しています。

簡単なアプリケーションと言えど、一応お勉強用にそちらも試してみました。

gulp-pleeeaseで圧縮/非圧縮を切り替える

gulp-pleeeaseを使うと、デフォルトでは圧縮されてしまいますが、開発時にはちょっとつらい。
開発時には非圧縮のまま、でもvendor prefixはつけてほしいからpleeeeaseの処理をかませたい。

minifierの設定をtrue/false切り替えるだけ…なんですが。

色んなサイトで書いている方法でやってみても何か反映されない。
Pleeease公式では専用の設定ファイルを使うのでちょっと書き方が違うっぽい。
gulpとかpleeeaseのバージョンによるのかな?と思いつつ、試してみました。

結論としては

gulpfile.js
gulp.task('css', function() {
  return gulp.src('assets/stylesheets/app.scss')
    .pipe(sass({ style: 'expanded' }))  // CSS展開のスタイル選択
    .pipe(please({
      minifier: false // 圧縮しない
    }))
    .pipe(gulp.dest('build/assets/css/'));  // 出力先
});

pleeeaseに渡すオブジェクトでminifier: Booleanを設定すれば圧縮・非圧縮が切り替わりました。optimizersって何だったんだろう…。

コマンド入力でGulpに引数を渡したい

開発用ビルド(非圧縮)と本番用ビルド(圧縮)を切り替えたい。ので、コマンドライン入力でビルド環境を切り替えたい。Gulpではどうやるんだろう…と思って調べてみると、Gulpのレシピ(Pass arguments from the command line)に書いてあったのでそのまま拝借。

minimistっていうのを使うといけるっぽい。ぽい。

gulpfile.js
var minimist = require('minimist'); // CLI入力を解析

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'development' } // NODE_ENVに指定がなければ開発モードをデフォルトにする
};

// コマンドラインの入力を解析
var options = minimist(process.argv.slice(2), knownOptions),
    isProduction = (options.env === 'production') ? true : false;

console.log('[build env]', options.env, '[is production]', isProduction);
$ gulp
[build env] development [is production] false
...()

おお、いい感じ。

これを使い、先ほどのminifierの設定を切り替えて、

$ gulp --env production   // production build
$ gulp   // development build

で、圧縮・非圧縮を切り替えることができました。


CSSのあれこれをGulpにさせてみた

完成ソースを晒してみます。
もっとこうすればいいよ、とかあればご教授いただけると幸いです。

gulpfile.js
/**
 * requires
 */
var gulp = require('gulp'),
    minimist = require('minimist'), // CLI入力を解析
    please = require('gulp-pleeease'),
    sass = require('gulp-ruby-sass'); // output styleを選べるので、gulp-sassではなくこちらを採用

/**
 * settings
 */
var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'development' } // NODE_ENVに指定がなければ開発モードをデフォルトにする
};
// コマンドラインの入力を解析
var options = minimist(process.argv.slice(2), knownOptions),
    isProduction = (options.env === 'production') ? true : false;

console.log('[build env]', options.env, '[is production]', isProduction);

/**
 * tasks
 */
gulp.task('css', function() {
  return gulp.src('assets/stylesheets/app.scss')
    .pipe(sass({ style: 'expanded' }))  // CSS展開のスタイル選択
    .pipe(please({
      autoprefixer: {"browsers": ["last 4 versions", "Android 2.3"]},  // ベンダープレフィックス対応バージョンの指定
      minifier: isProduction // ビルド環境に応じて圧縮
    }))
    .pipe(gulp.dest('build/assets/css/'));  // 出力先
});

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

gulp.task('default', ['css']);

使い方

本番用ビルド(圧縮)

$ gulp --env production

開発用ビルド(非圧縮)

$ gulp

開発中に変更を監視して開発用ビルド

$ gulp watch

参考リンク