中小規模向けウェブサイト制作いい感じgulp環境を考えてみた

中小規模とは具体的にどのくらいを指すのかとか、いい感じとはゴール設定はどこなのかとかを、あえて曖昧にすることでgulpfileを晒しやすくする。 
目安としては、

+ 複雑な依存関係を伴わないAltJSの処理
+ 静的ページ、または動的ページのテンプレートをPug(Jade)で作成
+ sass
+ ローカルサーバー機能
+ build機能

くらいあれば充分でございますと。
要は「ゴリゴリに開発環境を整えるほど予算も納期もない案件なんだけど、sass,AltJS,pugあたりを便利にトランスパイルさせたい、ついでにちょっとした便利機能が欲しい、というあたりを満足できればゴールとしている。
ちなみに、この環境ではAltJSはCoffeeScriptを使用しているが、そこは案件によるところなので適宜Babelなどに変えていけばいい。
ユニットテストがないじゃないかと怒られそうだが、そのうち考えておく。

## ファイル

```javascript:package.json
{
  "scripts": {
    "gulp": "gulp",
    "start": "gulp develop",
    "build": "gulp build"
  },
  "devDependencies": {
    "del": "^2.2.2",
    "gulp": "^3.9.1",
    "gulp-babel": "^6.1.2",
    "gulp-coffee": "^2.3.2",
    "gulp-pug": "^3.1.0",
    "gulp-sass": "^2.3.2",
    "gulp-slack": "^0.1.2",
    "gulp-webserver": "^0.9.1",
    "run-sequence": "^1.2.2"
  }
}
```

```javascript:gulpfile.js
var gulp = require('gulp'),
os = require('os'),
del = require('del'),
runSequence = require('run-sequence'),
webserver = require('gulp-webserver'),
pug = require('gulp-pug'),
sass = require('gulp-sass'),
coffee = require('gulp-coffee'),
slack = require('gulp-slack')({
  url: '*Your Webhook URL*'
});

const config = {
  src: 'src',
  dist: 'public',
  assets: 'assets',
};


// IPアドレスを取得
getIPAddress = ()=>{
  var ifaces = os.networkInterfaces();
  var ipaddress;
  Object.keys(ifaces).forEach((ifname) =>{
    ifaces[ifname].forEach((iface)=>{
      if(iface.family !== 'IPv4' || iface.internal != false){
        return;
      }
      ipaddress = iface.address;
    });
  });
  return ipaddress;
};
var ipaddress = getIPAddress();


//Webサーバー
gulp.task('webserver', () => {
  return gulp.src(config.dist)
  .pipe(webserver({
    livereload: true, //ライブリロード
    host: '0.0.0.0' // IPアドレスで起動
  }))
  //slackにアドレスを通知。
  .pipe(slack(`http://${ipaddress}:8000/`));
});

//コピー
gulp.task('copy', ()=>{
  return gulp.src(`./${config.assets}/**`)
  .pipe(gulp.dest(`./${config.dist}`))
});

gulp.task('copy:watch', ()=>{
  gulp.watch(`${config.assets}/**`, ['copy']);
});

//pug
// _ アンダーバーから始まる、インクルードファイルをコンパイルしない
const watchPugFile = `${config.src}/**/*.pug`;
const pugFiles = [watchPugFile, `!./${config.src}/**/_*.pug`];
gulp.task('pug:dev', () => {
  return gulp.src(pugFiles)
  .pipe(pug({
    pretty: true
  }))
  .pipe(gulp.dest(config.dist))
});

gulp.task('pug', () => {
  return gulp.src(pugFiles)
  .pipe(pug({
    pretty: false
  }))
  .pipe(gulp.dest(`./${config.dist}/`))
});

gulp.task('pug:watch', () =>{
  return gulp.watch(watchPugFile, ['pug:dev']);
});

//sass
const watchSassFile = `${config.src}/**/*.scss`;
const sassFiles = [watchSassFile, `!./${config.src}/**/_*.scss`];
gulp.task('sass', () => {
  return gulp.src(sassFiles)
  .pipe(sass.sync().on('errer', sass.logError))
  .pipe(gulp.dest(config.dist))
});

gulp.task('sass:watch', () =>{
  return gulp.watch(watchSassFile, ['sass']);
});


//coffee
const coffeeFiles = `${config.src}/**/*.coffee`;
gulp.task('coffee', () =>{
  return gulp.src(coffeeFiles)
  .pipe(coffee({bare:false}))
  .pipe(gulp.dest(config.dist));
});

gulp.task('coffee:watch', () =>{
  return gulp.watch(coffeeFiles, ['coffee']);
});


//clean
gulp.task('clean', ()=>{
  return del(config.dist);
});

//watch
gulp.task('watch', ['pug:watch', 'sass:watch', 'coffee:watch', 'copy:watch']);

//task
gulp.task('develop', ['webserver', 'watch']);
gulp.task('default', ['develop']);
gulp.task('build', ()=>{
  return runSequence(
    'clean',
    ['pug', 'sass', 'coffee', 'copy']
  );
});
```

ファイルの記述としては少し冗長なところもあるが、どんな仕事をしているのか人間が目視で確認しやすいという点ではまあまあな感じにできた。

## ディレクトリ構成

+ src : AltJS、sass、pugなどトランスパイルが必要なファイル
+ assets : imgファイル、素のHTMLファイル、素のJSファイル、素のCSSファイルなど、トランスパイルが必要ないファイル
+ public : gulpによって生成される成果物ファイル

## コマンド

### 開発中

普段の作業は

```Bash
npm run start
```

しておけば、srcディレクトリやassetsディレクトリを監視して、成果物をもりもりpublicディレクトリに生成してくれる。
srcディレクトリの中でpugファイルを書けばpublicにHTMLファイルにしてくれるし、sassを書けばCSSに、coffeeファイルを書けばjsファイルとして書き出してくれる。
assetsには画像ファイルを置けばいい。他には、各種外部ライブラリや既にあるHTML,CSS,JSファイルなどがあればこれもassetsに置いておけばいい。
ついでに8000番ポートにローカルウェブサーバーを立ち上げて、ライブリロードまでしてくれるようになる。
さらにローカルウェブサーバーのURLをSlackに通知してくれるので、スマホやタブレット、Windows機などの検証端末での検証が捗る。
開発環境のネットワークの設定によってはそのままではうまくいかないかもしれないが、個人的にはこの機能をつけられたことが一番嬉しかった。
IPアドレスの取得方法についてはtaikiken先生の[こちらの記事が参考になった](http://www.inazumatv.com/contents/archives/9885)。

slack通知機能はgulpfileの

```javascript
slack = require('gulp-slack')({
  url: '*Your Webhook URL*'
});
```

この部分に任意のWebhookURLを入れればいい。


### 納品物

開発が進みめでたくサーバーにアップロードするときは

```Bash
npm run build
```

と打てばいい。
publicディレクトリを一旦消して再構築かけているだけなのでminifyとか画像最適化など特別なことは行なっていないが、「ビルドするぞ」という気持ちを具現化して実行できるので仕事した気分になれる。

## まとめ

もう少し複雑なこともやらせてあげたい気もするが、高機能化は複雑化につながりその先には開発環境のメンテナンスという本末転倒な未来が待っているので、案件規模と相談して、こんなものではないかなと。

### 追記

+ 2016/10/26 新規ファイルが監視できない問題を修正。