【gulp】pug, scss, 画像の圧縮環境を導入・読解してみた。

## 自己紹介
* gulpが何かはわかる
* gulpの環境が整っていれば、とりあえず使える
* pug,sassは書ける
* gulp環境を自分で作るのは初めて
* gulp大抵コピペでどうにかなるけど、ちゃんと理解してカスタマイズできるようにしたい。


## 導入手順
### 1. 作業ディレクトリを作成、移動
```bash
$ mkdir gulp-sample
$ cd gulp-sample
```


### 2. srcフォルダとwww(dist)フォルダを作る。
適当に内容を書いておく。
今回は1ページの簡易なLPの想定。
pugは1ファイルのみ、sass, js, imagesフォルダを用意。
構造は以下の通り。

```
src--
	 |--sass
	   |-main.scss
	 |--js
	   |-main.js
	 |--images
	   |-sample.jpg
	 |-index.pug

www--
	 |--assets
	   |--css
		 |-main.css
	   |--js
		 |-main.js
	   |--images
		 |-sample.jpg
	 |-index.html
```


### 3. package.jsonを作る
```bash
$ npm init -y
```

### Gulp をインストール
```bash
$ npm i -D gulp@3.9.0
```

※現時点で最新のGulp4系は、いろいろ文法変わっててエラーを吐かれてダルかった。
→ググって出てくるgulp情報は3系のものが多め
→ひとまず3.9にしとくのが無難と判断

### 4. 必要なモジュールを入れる。
```bash
$ npm i -D module1 module2
```
半角スペースを挟むことで複数指定もできる。名前の打ち間違いに注意。

#### 必須系
* browser-sync（同期ブラウジング
* gulp-notify（通知
* gulp-plumber（エラーによる強制停止防止、notifyとセットで使う

#### sass系
* gulp-sass（コンパイラー
* gulp-autoprefixer
* gulp-clean-css（css圧縮

#### pug系
* gulp-pug（コンパイラー

#### 画像系 
* gulp-imagemin（画像圧縮
* gulp-changed（フォルダ比較?
* imagemin-pngquant（画像圧縮率を高めるために必要なプラグイン
* imagemin-mozjpeg（同上


#### ※ 間違って必要ないモジュールを入れてしまった場合
package.jsonから、必要ないモジュール情報を削除。
その後

```bash
$ npm i
```
Npm installだけ叩くとpackage.jsonに書いてあるモジュールのみインストールするから。


### 5. gulpfile.jsを用意。
ソースコード（コピペ用

```js
var gulp = require("gulp");
var plumber = require("gulp-plumber");
var notify = require("gulp-notify");
var browserSync = require("browser-sync");

var sass = require("gulp-sass");
var autoprefixer = require("gulp-autoprefixer");
var minifycss = require('gulp-clean-css');

var pug = require("gulp-pug");

var imagemin = require('gulp-imagemin');
var changed = require('gulp-changed');
var pngquant = require('imagemin-pngquant');
var mozjpeg = require('imagemin-mozjpeg');


gulp.task('default', [ 'browser-sync', 'watch', 'pug', 'sass', 'jsCopy', 'images']);

// sass
gulp.task('sass', () => {
  gulp.src("./src/sass/*scss")
      .pipe(plumber({
          errorHandler: notify.onError("Error: <%= error.message %>")
      }))
      .pipe(sass())
      .pipe(autoprefixer({
        browsers: ['last 2 version', 'iOS >= 10', 'Android >= 5', 'ie >= 11'],
        cascade: false
      }))
      .pipe(minifycss())
      .pipe(gulp.dest("./www/assets/css/"))
});

// pug
gulp.task('pug', () => {
  var option = {
      pretty: true
  }
  gulp.src("./src/*.pug")
      .pipe(plumber({
          errorHandler: notify.onError("Error: <%= error.message %>")
      }))
      .pipe(pug(option))
      .pipe(gulp.dest("./www/"))
});

// js-copy
gulp.task('jsCopy', () => {
  gulp.src("./src/js/*.js")
    .pipe(plumber({
        errorHandler: notify.onError("Error: <%= error.message %>")
    }))
    .pipe(gulp.dest("./www/assets/js/"));
});

// images
gulp.task('images', () => {
  return gulp.src('./src/images/**/*.{png,jpg,gif,svg}')
    .pipe(changed('./www/assets/images/'))
    .pipe(imagemin([
      pngquant({
        quality: '65-80',
        speed: 1,
        floyd: 0,
      }),
      mozjpeg({
        quality: 85,
        progressive: true
      }),
      imagemin.svgo(),
      imagemin.optipng(),
      imagemin.gifsicle()
    ]))
    .pipe(gulp.dest('./www/assets/images/'))
    .pipe(notify('images task finished'));
});

gulp.task('watch', () => {
  gulp.watch(['./src/*.pug'], ['pug']);
  gulp.watch(['./src/sass/**'], ['sass']);
  gulp.watch(['./src/js/**'], ['jsCopy']);
});

gulp.task('browser-sync', () => {
  browserSync({
    server: {
      baseDir: "./www/"
    }
  });
  gulp.watch("./www/*.html", ['reload']);
  gulp.watch("./www/assets/css/*.css", ['reload']);
  gulp.watch("./www/assets/js/*.js", ['reload']);
});

gulp.task('reload', () => {
  browserSync.reload();
});
```

あんまりスマートじゃないコードの自覚はあります…はい…
js苦手やねん…


### 6. gulpの起動
`package.json`の、scripts部分に以下を追記。

```js
"scripts": {
    "start": "gulp",// ←追記
    "test": "echo \"Error: no test specified\" && exit 1"
  },
```

その後、

```bash
$ npm run start
```


※ `npx` とかでも動くけど、nodeのバージョンとか考慮するとこの方が安全。


## gulpfileの解説（わかる範囲
部分部分を解説。理解が甘いとこあるかも。

### モジュール読み込み
`npm i`した子たちを処理で使えるように変数に格納。

```js
var gulp = require("gulp");
var plumber = require("gulp-plumber");
var notify = require("gulp-notify");
var browserSync = require("browser-sync");

var sass = require("gulp-sass");
var autoprefixer = require("gulp-autoprefixer");
var minifycss = require('gulp-clean-css');

var pug = require("gulp-pug");

var imagemin = require('gulp-imagemin');
var changed = require('gulp-changed');
var pngquant = require('imagemin-pngquant');
var mozjpeg = require('imagemin-mozjpeg');
```

### default
defaultタスク。これがないとgulpちゃんがおこ。
起動コマンドを叩いた瞬間に走って欲しいコマンドをまとめて書いておく。（全部書かなくてもいい

```js
gulp.task('default', [ 'browser-sync', 'watch', 'pug', 'sass', 'jsCopy', 'images']);
```


### sassタスク
タスクの読み方は [別記事→](https://qiita.com/dorara/items/9e491fb00bc2ff063647)

Sassのエラーをチェックして、コンパイルして、プレフィックスつけて、圧縮して、吐き出すタスク。
プレフィックスはいろいろバージョン指定できるっぽい。

```js
gulp.task('sass', () => {
  gulp.src("./src/sass/*scss")
      .pipe(plumber({
          errorHandler: notify.onError("Error: <%= error.message %>")
      }))
      .pipe(sass())
      .pipe(autoprefixer({
        browsers: ['last 2 version', 'iOS >= 10', 'Android >= 5', 'ie >= 11'],
        cascade: false
      }))
      .pipe(minifycss())
      .pipe(gulp.dest("./www/assets/css/"))
});
```


### pugタスク
Sassよりわかりやすい。
エラーチェックして、コンパイルして、出力。
`pretty: true`というオプションは、htmlを整形するか否か。

```js
gulp.task('pug', () => {
  var option = {
      pretty: true
  }
  gulp.src("./src/*.pug")
      .pipe(plumber({
          errorHandler: notify.onError("Error: <%= error.message %>")
      }))
      .pipe(pug(option))
      .pipe(gulp.dest("./www/"))
});
```


### jsのコピー
Babel対応したかったけどモジュールが他にもいろいろ必要で、今回は省略。
とりあえず`src`にあるjsをそのまま`www`へ。

```js
gulp.task('jsCopy', () => {
  gulp.src("./src/js/*.js")
    .pipe(plumber({
        errorHandler: notify.onError("Error: <%= error.message %>")
    }))
    .pipe(gulp.dest("./www/assets/js/"));
});
```

さほどjsを使わないLPなら問題ない…気がする


### 画像圧縮タスク
changed()で `www`と比較して、未圧縮のファイルのみ圧縮してくれる。
圧縮率などをいろいろ設定できるっぽいが、とりあえず脳死コピペ。

```js
gulp.task('images', () => {
  return gulp.src('./src/images/**/*.{png,jpg,gif,svg}')
    .pipe(changed('./www/assets/images/'))
    .pipe(imagemin([
      pngquant({
        quality: '65-80',
        speed: 1,
        floyd: 0,
      }),
      mozjpeg({
        quality: 85,
        progressive: true
      }),
      imagemin.svgo(),
      imagemin.optipng(),
      imagemin.gifsicle()
    ]))
    .pipe(gulp.dest('./www/assets/images/'))
    .pipe(notify('images task finished'));
});
```


### 監視タスク
watchメソッド。gulpが標準搭載してるメソッド。
第一引数で指定したディレクトリの変更を感知して、第二引数のtaskを実行する。
つまい`src/`フォルダ側を変更したら、それをコンパイルするタスクを即座に動かすようにできる。

```js
gulp.task('watch', () => {
  gulp.watch(['./src/*.pug'], ['pug']);
  gulp.watch(['./src/sass/**'], ['sass']);
  gulp.watch(['./src/js/**'], ['jsCopy']);
});
```

### 同期ブラウジング
ブラウジング。今回は`www/`以下に `index.html`を置くので、そこをブラウジングするよう指示。
またタスクによりコンパイルされ`www/`以下の各ファイルが書き換わったタイミングで、`reload`タスクが動くように指示。

```js
gulp.task('browser-sync', () => {
  browserSync({
    server: {
      baseDir: "./www/"
    }
  });
  gulp.watch("./www/*.html", ['reload']);
  gulp.watch("./www/assets/css/*.css", ['reload']);
  gulp.watch("./www/assets/js/*.js", ['reload']);
});

gulp.task('reload', () => {
  browserSync.reload();
});

```

上記の監視タスク`watch`と合わせて、
1. `src/`のpug, sass等を書き換える
2. watchが発動し各タスクが実行
3. タスクにより pug,sass がコンパイルされ、`www/`に保存
4. `www/`のファイルが書き換わったら、ブラウザをリロード

という流れで、pug, sass側の変更が即座にブラウザで反映されるように。

## 参考記事
Gulpのタスク書き方→
https://qiita.com/ferretdayo/items/47937cfb38babcf17a20
Auto-prefix→
[gulp-autoprefixerを使ってCSSのベンダープレフィックス付与を自動化する - $shibayu36->blog;](https://blog.shibayu36.org/entry/2016/07/20/102641)
画像圧縮→
[Gulpで画像圧縮を簡単に自動化するタスクの2018年版 &#8211; 『Gulp』 | webmanab.html／ウェブまなぶ](https://webmanab-html.com/tip/gulp-imagemin-2018/)