gulp開発環境テンプレート

`webpack、npm-scripts`に押され気味の`gulp`ですが、まだまだ案件で使われることも多いと思います。
そんな案件にアサインされたときにサクッと環境を整える為に投稿。
想定しているサイトの規模は小〜中規模案件。

`gulp`の導入手順などは割愛。

これから初めて使うという方はこの辺が参考になるかと思います。
<a href="https://liginc.co.jp/web/tutorial/117900" target="_blank">Gulp.js入門 – コーディングを10倍速くする環境を作る方法まとめ</a>

階層構造はこんな感じ

````
hoge
  ├─ dist
  │  ├─ css
  │  │  └─ *.css
  │  ├─ img
  │  │  └─ *
  │  ├─ js
  │  │  └─ *.js
  │  └─ *.html
  ├─ src
  │  ├─ ejs
  │  │  └─ *.ejs
  │  ├─ js
  │  │  └─ *.js
  │  ├─ sass
  │  │  └─ *.scss
  │  └─ spriteimg
  │     └─ *
  ├─ gulpfile.js
  └─ package.json
````

`package.json`はこんな感じ

````json:package.json
{
  "name": "hoge",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "browserify": "^14.1.0",
    "gulp": "^3.9.1",
    "gulp-autoprefixer": "^3.1.1",
    "gulp-cssmin": "^0.1.7",
    "gulp-ejs": "^3.0.0",
    "gulp-imagemin": "^3.2.0",
    "gulp-rename": "^1.2.2",
    "gulp-sass": "^3.1.0",
    "gulp-uglify": "^2.1.2",
    "gulp-webserver": "^0.9.1",
    "gulp.spritesmith": "^6.4.0",
    "imagemin-guetzli": "^0.1.5",
    "watchify": "^3.9.0"
  }
}
````

`gulpfile`はこんな感じ

````js:gulpfile.js
var gulp = require('gulp');
var ejs = require('gulp-ejs');
var sass = require('gulp-sass');
var rename = require('gulp-rename');
var autoprefixer = require('gulp-autoprefixer');
var spritesmith = require('gulp.spritesmith');
var webserver = require('gulp-webserver');
var cssmin = require('gulp-cssmin');
var uglify = require('gulp-uglify');
var imagemin = require('gulp-imagemin');
var imageminGuetzli = require('imagemin-guetzli');
var browserify = require('browserify');
var watchify = require('watchify');

gulp.task('ejs', function() {
    return gulp.src(['src/ejs/*.ejs', '!src/ejs/_*.ejs']) // ファイル名に_が付いたejsファイルはhtmlとして出力しない
    .pipe(ejs())
    .pipe(rename({
        extname: '.html'
    }))
    .pipe(gulp.dest('dist/'));
});

gulp.task('sass', function() {
    return gulp.src(['src/sass/*.scss', 'src/sass/**/*.scss'])
    .pipe(sass())
    .pipe(autoprefixer({
        browsers: ['iOS 7', 'android 2.1'] // レギュレーションに合わせた設定
    }))
    .pipe(gulp.dest('dist/css/'));
});

gulp.task('sprite', function () {
    var spriteItem = gulp.src('src/spriteimg/*.png') //スプライトする画像
    .pipe(spritesmith({
        imgName: 'sprite.png',
        cssName: '_sprite.scss',
        imgPath: 'img/sprite.png',
        cssFormat: 'scss',
        cssVarMap: function (sprite) {
            sprite.name = 'sprite-' + sprite.name;
        }
    }));
    spriteItem.img.pipe(gulp.dest('dist/img/')); //imgNameで指定したスプライト画像の保存先
    spriteItem.css.pipe(gulp.dest('src/sass/')); //cssNameで指定したcssの保存先
});

gulp.task('browserify', function() {
    return jscompile(false);
});

gulp.task('watchify', function() {
    return jscompile(true);
});

function jscompile(is_watch) {
    var bundler;
    if (is_watch) {
        bundler = watchify(browserify('src/js/main.js'));
    } else {
        bundler = browserify('src/js/main.js');
    }
    function rebundle() {
        return bundler
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('dist/js'));
    }
    bundler.on('update', function() {
        rebundle();
    });
    bundler.on('log', function(message) {
        console.log(message);
    });
    return rebundle();
}

// ウォッチタスク ejs/sass/jsが保存されると自動でコンパイル
gulp.task('watch', function() {
    gulp.watch(['src/ejs/**/*.ejs', 'src/ejs/*.ejs', '!src/ejs/common/_*.ejs'], ['ejs']);
    gulp.watch(['src/sass/*.scss', 'src/sass/**/*.scss'], ['sass']);
    gulp.watch(['src/js/main.js'], ['watchify']);
});

// リリース用　画像圧縮、css/js難読化
gulp.task('cssmin', function () {
    return gulp.src('dist/css/*.css')
    .pipe(cssmin())
    .pipe(gulp.dest('dist/css'));
});

gulp.task('uglify', function() {
    return gulp.src(['dist/js/*.js'])
    .pipe(uglify())
    .pipe(gulp.dest('dist/js/'));
});

gulp.task('imgmin', function () {
    return gulp.src('dist/img/*')
    .pipe(imagemin([imageminGuetzli()]))
    .pipe(gulp.dest('dist/img'))
});

gulp.task('release', ['cssmin', 'imgmin', 'uglify'], function() {
    return gulp.src(['dist/css/*.css', 'dist/img/*', 'dist/js/*.js']);
});

// 参照・ライブリロード用WEBサーバ
gulp.task('webserver', function() {
  gulp.src('dist/')
    .pipe(webserver({
      livereload: true,
      directoryListing: true,
      open: false
    }));
});
````

## ざっと解説

仮想サーバーやスプライト画像は必要ない場合は、それに応じたタスクを省いて問題ありません。

|出力されるファイルなど|gulpのタスク|
|----|----|
|html|gulp-ejs|
|css|gulp-sass/gulp-cssmin/gulp-autoprefixer|
|js|browserify/watchrify/gulp-uglify|
|img|gulp-imagemin/imagemin-guetzli|
|スプライト画像|gulp.spritesmith|
|仮想サーバー|gulp-webserver|

`autoprefixer`のバージョン指定は直近のレギュレーションだった`iOS7/Android2.1`を指定。
もっと簡潔な書き方や、違うパッケージの方がいいよ！などありましたら教えて欲しいです！