gulp-sassとgulp-postcssで快適コンパイル環境を構築

[gulp-sass](https://www.npmjs.com/package/gulp-sass)と[gulp-postcss](https://www.npmjs.com/package/gulp-postcss)を組み合わせると、快適なCSSのコンパイル環境を実現できます。
Sassのコンパイルはgulp-sassで行い、ポストプリセッサーであるgulp-postcssにその後の処理を連携させるイメージです。

**※このエントリーは当初「gulp-sassとgulp-cssnextで快適コンパイル環境を構築」というタイトルで公開していましたが、[gulp-cssnext](https://github.com/MoOx/gulp-cssnext)が非推奨プラグインとなり、PostCSSを使ったやり方が主流になってきたため、[gulp-postcss](https://www.npmjs.com/package/gulp-postcss)を用いた内容に全面的に修正しました。**

# 基礎知識

## gulp-sassについて

gulpでSassのコンパイルを行うnpmパッケージです。
[libsass](https://github.com/sass/libsass)を使っているため、[gulp-ruby-sass](https://www.npmjs.com/package/gulp-ruby-sass)や[gulp-compass](https://www.npmjs.com/package/gulp-compass)と比べて処理が高速で、
Rubyに依存しないため環境の構築・共有がしやすい利点があります。

## gulp-postcssについて

gulp-postcssは、多様なプラグインを用いてCSSを変換するポストプロセッサーです。
プラグインによって様々な処理が可能になりますが、今回はCSSの先行実装を現在のブラウザが解釈できる構文に変換する[postcss-cssnext](https://www.npmjs.com/package/postcss-cssnext)というプラグインのみを使用したいと思います。
cssnext自体にも色々な機能がありますが、例えばベンダープレフィックスの付与を自動で行う[autoprefixer](https://github.com/postcss/autoprefixer)などの役割を、オールインワンで提供してくれるもの、と思ってもらえればいいでしょう。

# 使い方

## インストール

プロジェクトのルートディレクトリで以下のコマンドを実行してください。

```
$ npm i gulp gulp-sass gulp-postcss postcss-cssnext
```

## gulpfile.jsの設定

ルートディレクトリ直下に`gulpfile.js`を設置し、以下のようにタスクを設定してください。

```gulpfile.js
var gulp = require('gulp');
var sass = require('gulp-sass');
var postcss = require('gulp-postcss');
var cssnext = require('postcss-cssnext');

var paths = {
  'scss': 'src/css/',
  'css': 'dist/css/'
}

gulp.task('scss', function() {
  var processors = [
      cssnext()
  ];
  return gulp.src(paths.scss + '**/*.scss')
    .pipe(sass())
    .pipe(postcss(processors))
    .pipe(gulp.dest(paths.css))
});
```

## タスクの実行

以下のコマンドを実行すると、Sassのコンパイルと、postcssによるポストプロセッサーの処理を、連携して行うことができます。

```
$ gulp scss
```

## ベンダープレフィックスの付与

例えば、CSSの先行実装である`display: flex;`を記述してみましょう。

```style.scss
.header {
  display: flex;
}
```

すると、以下のように変換後のCSSには適切なベンダープレフィックスが付与されました。
これは、Sassファイル側でmixinなどを使ってプレフィックスを付与しなくても、その後のgulpタスクでcssnextが自動で処理してくれています。

```style.css
.header {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}
```

## 対象ブラウザの指定

cssnextには、その他にもカスタムプロパティや演算、カスタムセレクタ等といった[様々な機能](http://cssnext.io/features/)がありますが、
どの機能を使用するかは「対象ブラウザ」に応じて自動で判別して処理を行ってくれます。

デフォルトでも『なんとなくモダンブラウザ+α』という感じで対応してくれていますが、
プロジェクトの要件等に応じて対象ブラウザや推奨環境を設定しておくと良いでしょう。

以下の設定だと「各主要ブラウザの最新2バージョンまで対応」という指定になります。

```gulpfile.js
gulp.task('scss', function() {
  var processors = [
      cssnext({browsers: ['last 2 version']})
  ];
  return gulp.src(paths.scss + '**/*.scss')
    .pipe(sass())
    .pipe(postcss(processors))
    .pipe(gulp.dest(paths.css))
});
```
※より細かい指定方法については[こちら](https://github.com/ai/browserslist#readme)を参考にしてください。

## 特定の機能の有効化／無効化

ブラウザの指定だけでなく、cssnextの各機能は強制的に有効化または無効化することもできます。
各機能のON/OFFを行うには`features`の設定で、各項目を`true`または`false`を記述します。

```gulpfile.js
gulp.task('scss', function() {
  var processors = [
      cssnext({
        browsers: 'last 2 versions',
        features:{
          customProperties: true,
          calc: true,
          customMedia: true,
          mediaQueriesRange: true
        }
  ];
  return gulp.src(paths.scss + '**/*.scss')
    .pipe(sass())
    .pipe(postcss(processors))
    .pipe(gulp.dest(paths.css))
});
```
さらに、各機能ごとに細かい設定を行うこともできますが、詳しいオプションについては[各プラグイン](http://cssnext.io/features/)のページを参考にしてください。

# まとめ＆注意点

## libsass + PostCSSのメリット

以上のように、gulp-sassとgulp-postcssを組み合わせることで、快適なCSSのコンパイル環境を実現することができます。

基本的なコーディングはlibsassで行い、補佐的な様々な便利機能をPostCSSが補ってくれるという、いいとこ取りできるのが最大の利点ではないでしょうか？

gulpのタスクとしては、プリプロセッサーとポストプロセッサーの『二段構え』という形になりますが、こちらの[ベンチマーク結果](https://github.com/postcss/benchmark#user-content-preprocessors)を見ても分かる通り、libsassもPostCSSも、Ruby Sass等に比べると非常に高速なので、両方の処理を合わせても、体感的にはほとんど気になるレベルではないでしょう。

## 注意点

[postcss-cssnext](https://www.npmjs.com/package/postcss-cssnext)は、様々な機能をオールインワンで実現してくれますが、実際はcssnext自体も復数のPostCSSプラグイン群から構成されています。

また、PostCSS本体やそのプラグイン等は、各々別個のプロジェクトとして日々アップデートされていることは、認識しておいた方が良さそうです。

なので、個々の機能の使い方で分からない点があったり、バグや不具合らしきものを見つけたら、[各プラグイン](http://cssnext.io/features/)のGitHubリポジトリを参照して、場合によっては開発状況やIssuesの報告をチェックしておくようにしましょう。

# おまけ

## gulp-sass＆gulp-postcssのスターターキット

実際に上記のやり方を体験していただけるスターターキットを用意しました。
ぜひGitHubからcloneして、お手元の環境でお試しください。

- [littlebirdjp/staticsite-starterkit2: Starter Kit for a Simple Website Development.](https://github.com/littlebirdjp/staticsite-starterkit2)

## PostCSS単体で使うには？

今回はlibsassと組み合わせる形で、補助的にPostCSSを導入する方法を解説しましたが、ポストプロセッサーであるPostCSSを単体で利用することも可能です。

ただしその際には、「Sassでおなじみのネストやミックスインぐらいは使いたい」と思うかもしれません。

そんな時は、[gulp-postcss](https://www.npmjs.com/package/gulp-postcss)の説明を参考に、以下のように復数のPostCSSプラグインを組み合わせて、CSSを変換してみてください。

```gulpfile.js
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var cssnext = require('postcss-cssnext');
var PostcssSimpleVars = require('postcss-simple-vars');
var PostcssNested = require('postcss-nested');
var PostcssMixins = require('postcss-mixins');
var PostcssImport = require('postcss-import');

var paths = {
  'src': 'src/',
  'dist': 'dist/'
}

gulp.task('css', function() {
  var processors = [
      cssnext(),
      PostcssMixins(),
      PostcssSimpleVars(),
      PostcssNested(),
      PostcssImport(),
  ];
  return gulp.src(paths.src + 'css/*.css')
    .pipe(postcss(processors))
    .pipe(gulp.dest(paths.dist + 'css/'))
});
```

- [postcss-simple-vars](https://www.npmjs.com/package/postcss-simple-vars) - Sassライクな変数を利用できるようにするプラグイン
- [postcss-nested](https://www.npmjs.com/package/postcss-nested) - Sassライクなネストを利用できるようにするプラグイン
- [postcss-mixins](https://www.npmjs.com/package/postcss-mixins) - Sassライクなmixinsを利用できるようにするプラグイン
- [postcss-import](https://www.npmjs.com/package/postcss-import) - Sassライクなimportを利用できるようにするプラグイン