gulp.js ハンズオン




## タスクランナー & ビルドツール とは
**Webフロントエンド開発におけるいろんな面倒な処理を自動でやってくれるツールです。**
最近のフロントエンド開発環境において必須といっても過言ではありません。

ちょっと前まではGrunt.jsが最も有名でスタンダードな選択肢でしたが、
最近では多くのフロントエンドエンジニア達が後発のGulp.jsに移行している感じがあります。
特に最近はWeb上の記事なども増えてきたので、取り入れるにはとてもいいタイミングと言えます。
**Gulp.jsはとても簡単でわかりやすいので、簡単に導入できます。**


また、タスクランナーのGUIアプリではCodeKitなどが挙げられます。

## CodeKit(有料GUIアプリ)との違い
* 慣れればCodeKitより簡単
* JSで設定を記述するので簡潔
* css保存したときなど反映がとても速い
* できることが多い
* 細かい設定ができる



## できること
   * **Webサーバー/ライブリロード（gulp-connect, browser-sync）**
   * **ライブリロードのみ（gulp-livereload）**
   * **Sass、Compass、CoffeeScript、Jadeなどのコンパイル**
   * HTMLからJade,markdown,プレーンテキストに変換（gulp-html2xxxx）
   * CSS中に点在したメディアクエリーをまとめる（gulp-combine-media-queries）
   * **CSSベンダープリフィックスの管理（gulp-autoprefixer）**
   * CSSプロパティ並び順整理（gulp-csscomb）
   * コードの連結（gulp-concat）
   * コードの圧縮（gulp-minify-html,）
   * コードの整形（gulp-prettify,）
   * CSSスプライト生成
   * 画像圧縮（gulp-imagemin）
   * markdownをPDFに変換（gulp-markdown-pdf）
   * 画像サイズ変換（gulp-image-resize）
   * コード構文チェック Lint
   * ファイル書き出し
   * 圧縮/解凍（gulp-zip,gulp-unzip,gulp-untar）
   * **FTPアップロード（gulp-ftp,gulp-sftp）**
   * 文字コード変換
   * 実体参照変換（gulp-entity-convert）
   * DataURI化（gulp-base64,gulp-css-base64,gulp-data-uri）
   * Bower（gulp-bower-files）
   * JSON,YAML,XML,PLIST,CSV の相互変換（gulp-convert,gulp-csv2json,gulp-xml2json）
   * HTMLテーブルをCSVに変換（gulp-table2csv）
   * サイトマップ作成（gulp-sitemap-files）
   * sitemap.xml生成（gulp-sitemap）
   * 通知センターに通知（gulp-notify）
   * Webページのスクリーンショット撮影（gulp-webshot）
   * Angular関連



##インストール
###グローバルへのインストール
> $ npm install -g gulp

`$ gulp -v` でバージョンが表示されたらOK



##プロジェクトへのインストール

サンプルプロジェクトを用意しました → [gulpHandsOn.zip](https://dl.dropboxusercontent.com/u/20071392/gulpHandsOn.zip)


###①プロジェクトフォルダ内にてnpmでパッケージ管理する準備
> $ npm init

※とりあえずエンター連打で問題ありません。
package.jsonが自動生成されます。

###②gulpをプロジェクトフォルダにインストール
> $ npm install --save-dev gulp

※"--save-dev"オプションはなくても問題ありませんが、これを着けることによって、package.jsonに開発用モジュールの欄に追記されます。

## gulp.jsを使う流れ

###①gulpfile.jsをプロジェクトフォルダに作成

###②必要なモジュールをインストール
> $ npm install --save-dev [パッケージ名]

###③`$ gulp [タスク名]` で起動
> $ gulp watch

`gulp`とだけ打てば"default"タスクが実行されるので基本的にそちらを使います。


## 使ってみる


###最もシンプルなタスク
```gulpfile.js

var gulp = require('gulp');

//デフォルトタスク
gulp.task('default', function() {
  console.log("デフォルトタスクが実行されたよ");
});

```


###タスクをつくってデフォルトで実行させる
```gulpfile.js

var gulp = require('gulp');


gulp.task('default', function() {
	console.log("デフォルトタスクが実行されたよ");
	gulp.run('hoge');//hogeタスクを実行
});


//hogeタスク
gulp.task('hoge', function() {
  console.log('hogeタスクが実行されたよ');
});

```





### LiveReload用のサーバーを立てる
```gulpfile.js

var gulp = require('gulp');
var browserSync = require("browser-sync");//サーバーを立ててライブリロードできるモジュール


//サーバーを立てるタスク
gulp.task("launch_browserSync", function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});


gulp.task('default', function() {
	console.log("デフォルトタスクが実行されたよ");

    gulp.run('launch_browserSync');
});


```




>
[BS] Local URL: http://localhost:3000
[BS] External URL: http://192.168.0.3:3000
[BS] Serving files from: ./

のようにコンソールに表示されるので、
自分のPCからはLoaclURLを、
他のPCやiPhone, AndroidからはExternal URLにアクセスすると、
自動でリロードされます。



### *.htmlを監視してLiveReload
```gulpfile.js

var gulp = require('gulp');
var browserSync = require("browser-sync");



gulp.task("launch_browserSync", function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});


//html用のタスク
gulp.task('html_task', function () {
  gulp.src('*.html')
    .pipe(browserSync.reload({stream:true}))
});



gulp.task('default', function() {
	console.log("デフォルトタスクが実行されたよ");

    gulp.run('launch_browserSync');	

    gulp.watch("*.html",["html_task"]);//*.htmlが保存されたら"html_task"を実行

});


```
同じようにしてタスクを追加すればcssやjsの保存時にライブリロードできます。

必要なパッケージ(browser-sync)を`npm install --save-dev [パッケージ名]`で追加してください。

> $ npm install --save-dev browser-sync




### *.sassを監視してコンパイル
```gulpfile.js

var gulp = require('gulp');
var browserSync = require("browser-sync");
var sass = require('gulp-ruby-sass');//sass用のモジュール(compassもコンパイル可能)



// sass用のタスク
// ※ compassを使う場合はconfig.rbも不必要。
//   @import "compass";だけでOK
gulp.task('sass_task', function() {
    gulp.src('sass/*.scss')//sassがある場所
        .pipe(sass({
            style: 'expanded',
            compass: true //これだけでcompass使用可能
        }))
        .pipe(gulp.dest('css/'))//コンパイル先のディレクトリ
        .pipe(browserSync.reload({stream:true}))//ライブリロード
});



gulp.task("launch_browserSync", function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});


gulp.task('html_task', function () {
  gulp.src('*.html')
    .pipe(browserSync.reload({stream:true}))
});



gulp.task('default', function() {
	console.log("デフォルトタスクが実行されたよ");

    gulp.run('launch_browserSync');	

    gulp.watch("*.html",["html_task"]);
    gulp.watch("sass/*.scss",["sass_task"]);//sassの監視

});


```












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


```gulpfile.js

var gulp = require('gulp');
var browserSync = require("browser-sync");
var sass = require('gulp-ruby-sass');
var pleeease = require('gulp-pleeease');//autoprefixerのモジュール



gulp.task('sass_task', function() {
    gulp.src('sass/*.scss')
        .pipe(sass({
            style: 'expanded',
            compass: true
        }))
		// 追加
        .pipe(pleeease({
            autoprefixer: {
                browsers: ['last 2 versions']
            },
            minifier: false
        }))
        .pipe(gulp.dest('css/'))
        .pipe(browserSync.reload({stream:true}))
});



gulp.task("launch_browserSync", function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});


gulp.task('html_task', function () {
  gulp.src('*.html')
    .pipe(browserSync.reload({stream:true}))
});



gulp.task('default', function() {
	console.log("デフォルトタスクが実行されたよ");

    gulp.run('launch_browserSync');	

    gulp.watch("*.html",["html_task"]);
    gulp.watch("sass/*.scss",["sass_task"]);//sassの監視

});


```








### gulp-plumberを使ってエラーが出てもgulpが止まらないようにする


```gulpfile.js

var gulp = require('gulp');
var browserSync = require("browser-sync");
var sass = require('gulp-ruby-sass');
var pleeease = require('gulp-pleeease');
var plumber = require('gulp-plumber');//追加


gulp.task('sass_task', function() {
    gulp.src('sass/*.scss')
        .pipe(plumber())//追加
        .pipe(sass({
            style: 'expanded',
            compass: true
        }))
        .pipe(pleeease({
            autoprefixer: {
                browsers: ['last 2 versions']
            },
            minifier: false
        }))
        .pipe(gulp.dest('css/'))
        .pipe(browserSync.reload({stream:true}))
});



gulp.task("launch_browserSync", function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});


gulp.task('html_task', function () {
  gulp.src('*.html')
    .pipe(browserSync.reload({stream:true}))
});



gulp.task('default', function() {
	console.log("デフォルトタスクが実行されたよ");

    gulp.run('launch_browserSync');	

    gulp.watch("*.html",["html_task"]);
    gulp.watch("sass/*.scss",["sass_task"]);//sassの監視

});


```

これでsassの環境は完成です。


##coffeeのコンパイル
coffeeのコンパイルは簡単です。




```coffeeのタスク
var coffee = require('gulp-coffee');


gulp.task("coffee_task", function() {
    gulp.src("coffee/*.coffee")
        .pipe(plumber())
        .pipe(coffee({bare: true}))//ラッピング無し
        .pipe(gulp.dest('js/'))
        .pipe(browserSync.reload({stream:true}))
});

```


```監視の処理をdefaultタスクへ追加
    gulp.watch("coffee/*.coffee",["coffee_task"]);
```




##jadeのコンパイル

```jadeのタスク
var jade = require('gulp-jade');


gulp.task('jade_task', function () {
    gulp.src('*.jade')
        .pipe(plumber())
        .pipe(jade({
            pretty: true
        }))
        .pipe(gulp.dest('.'))
        .pipe(browserSync.reload({stream:true}))
});

```

```監視の処理をdefaultタスクへ追加
    gulp.watch("*.jade",["jade_task"]);
```


## gulpfile.jsを保存した時にgulpを再起動する

```

var spawn = require('child_process').spawn;


 //defaultタスクとして使っていたタスクをstartとか別の名前にする
gulp.task("start", function() {
    gulp.run('launch_browserSync');
    gulp.watch("*.html",["html_task"]);
    gulp.watch("*.jade",["jade_task"]);
    gulp.watch("sass/*.scss",["sass_task"]);
    gulp.watch("coffee/*.coffee",["coffee_task"]);
});


//デフォルトタスクをこうする
gulp.task('default', function() {
    var process;
    function restart() {
        if (process) process.kill();
        process = spawn('gulp', ['start'], {stdio: 'inherit'});
    }
    gulp.watch('gulpfile.js', restart);
    restart();
});



```



## 最終的にこうなる

```



var gulp = require("gulp");
var browserSync = require("browser-sync");
var coffee = require('gulp-coffee');
var jade = require('gulp-jade');
var sass = require('gulp-ruby-sass');
var plumber = require('gulp-plumber'); 
var pleeease = require('gulp-pleeease');
var spawn = require('child_process').spawn;//gulpのautoReload
// npm install --save-dev gulp browser-sync gulp-coffee gulp-jade gulp-ruby-sass gulp-plumber  gulp-pleeease



gulp.task("launch_browserSync", function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});



gulp.task('sass_task', function() {
    gulp.src('sass/**/*.scss')
        .pipe(plumber())
        .pipe(sass({
            style: 'expanded',
            compass: true//これだけでcompass使用可能。config.rbとかも不必要。@import "compass";だけでおｋ
        }))
        .pipe(pleeease({
            autoprefixer: {
                browsers: ['last 2 versions']
            },
            minifier: false
        }))
        .pipe(gulp.dest('css/'))
        .pipe(browserSync.reload({stream:true}))
});


gulp.task("coffee_task", function() {
    gulp.src("coffee/*.coffee")
        .pipe(plumber())
        .pipe(coffee({bare: false}))
        .pipe(gulp.dest('js/'))
        .pipe(browserSync.reload({stream:true}))
});


gulp.task('jade_task', function () {
    gulp.src('*.jade')
        .pipe(plumber())
        .pipe(jade({
            pretty: true
        }))
        .pipe(gulp.dest('.'))
        .pipe(browserSync.reload({stream:true}))
});





gulp.task('html_task', function () {
  gulp.src('*.html')
    .pipe(browserSync.reload({stream:true}))
});

gulp.task("css_task", function() {
    gulp.src("css/*.css")
        .pipe(browserSync.reload({stream:true}))
});

gulp.task("js_task", function() {
    gulp.src("js/*.js")
        .pipe(browserSync.reload({stream:true}))
});


 
gulp.task("start", function() {
    gulp.run('launch_browserSync');

    gulp.run('jade_task');
    gulp.run('sass_task');
    gulp.run('coffee_task');

    gulp.watch("*.html",["html_task"]);
    gulp.watch("css/*.css",["css_task"]);
    gulp.watch("js/*.js",["js_task"]);

    gulp.watch("*.jade",["jade_task"]);
    gulp.watch("sass/*.scss",["sass_task"]);
    gulp.watch("coffee/*.coffee",["coffee_task"]);
});


//----------- gulp の auto reload -------------
gulp.task('default', function() {
    var process;
    function restart() {
        if (process) process.kill();
        process = spawn('gulp', ['start'], {stdio: 'inherit'});
    }
    gulp.watch('gulpfile.js', restart);
    restart();
});


```


##Sassでソースマップ


SassのデバッグにSource Mapsを使うべきたくさんの理由
http://dresscording.com/blog/sass/sass_sourcemaps.html