Electron の開発環境を gulp + babel で整える

# 概要

Electronとは、JavaScriptでデスクトップアプリが作れるツールです。
詳しくは前回の記事「[30分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで](http://qiita.com/nyanchu/items/15d514d9b9f87e5c0a29)」をご覧くだい。
これまではElectronを使ったアプリ開発方法について書いてきました。
今回はコードをガリガリ書いていく前に、開発環境を整えたいと思います。

今回はElectronの開発を ES6 + React でしたいと思いました。
そのための開発環境を gulp + babel を使って整えていきます。
この辺りは他の記事をかなり参考にしました。既に同じようなことをやっている方がたくさんいらっしゃいますが、個人的なメモも兼ねてまとめます。

参考記事
* [ぼくのかんがえたさいきょうのElectron](http://qiita.com/Quramy/items/90d61ff37ca1b95a7f6d)

# 何がしたいか

まずは何がしたいか、というところから話します。

* JavaScriptは ES6仕様 + React + Flux で書きたい
* ビルドはgulpで実行
* コードを変更したらElectronをLivereload

上記それぞれについて知らないという方はこの辺りを参考にすると良いかと思います。

* ES6について
 * [ES6時代のJavaScript](http://techlife.cookpad.com/entry/2015/02/02/094607)
* React + Flux について
 * [なぜ仮想DOMという概念が俺達の魂を震えさせるのか](http://qiita.com/mizchi/items/4d25bc26def1719d52e6)
* gulpについて
 * [ビルドツールまとめ。Gruntとかgulpとか (フロント寄り)](http://qiita.com/cognitom/items/db88babebeb869a4a198)
 * [現場で使えるgulp入門 - gulpとは何か](https://app.codegrid.net/entry/gulp-1)
* Livereloadについて
 * [LiveReloadが便利すぎる](http://qiita.com/martini3oz/items/7b9b73a5298d4e97b32a)

# 全体構成

まずは全体の構成から。
以下のように組みました。

```bash
.
├── bower.json
├── build # src内のコードをコンパイルしてここに配置
├── gulpfile.js 
├── images
│   └── icon.icns
├── index.html # 空っぽのHTML表示。build/app.jsを読みにいく。
├── main.js # Electronの初期設定はここで
├── package.json
└── src # 開発メインのコードはここに配置
    └── app.jsx
```

フロントエンドのパッケージ管理はbowerで、それ以外はpackage.jsonです。
ビルドツールはgulpを使うためgulpfile.jsを配置しています。

重要なのは、srcディレクトリとbuildディレクトリです。
開発メインとなるES6仕様のjsxファイルはsrcディレクトリに配置します。しかし、ES6仕様はまだ通常ブラウザでは動作しませんし、jsxファイルも当然認識されません。そこで、ES5仕様のjsファイルに変換したものをbuildディレクトリ下に配置してやることにします。そして、index.htmlからはbuildディレクトリ下のソースを読みにいくようにします。

# ビルドツールはgulpを採用

Node.jsでビルドツールといえばGruntが浮かびますが、最近はgulpが盛り上がってきているとのことで、使ってみました。
Gruntよりシンプルに書けて良さそうです。
インストールしておきます。

```bash
$ npm install gulp --save-dev
```


# コンパイル（ES6 -> ES5、 jsx -> js）

前述の通り、ES6仕様のコードはまだ通常ブラウザでは使えないので、ES5仕様に変換してあげる必要があります。
また、Reactで使用するjsxファイルもそのままでは使えないので通常のjsに変換してあげる必要があります。
jsxの変換はもっと簡単な方法でも可能ですが、表示するたびにコンパイルしていては重くなるのであらかじめやっておきます。
実はこの2つの作業、babelが一括でやってくれます。
まずはgulpプラグインのbabelをインストール。

```bash
$ npm install gulp-babel --save-dev
```

また、これからgulpのプラグインをたくさん入れていくのですが、毎回requireするのが面倒なのでまとめて読み込んでくれるプラグインをインストールしておきます。
こいつの地味なありがたさはしばらく書いていくとわかるでしょう。

```bash
$ npm install gulp-load-plugins --save-dev
```

早速gulpfile.jsを作成して中身を書いてみます。

```js:gulpfile.js
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

gulp.task('compile', function(){
  return gulp.src('src/**/*.{js,jsx}')
    .pipe($.babel({
      stage: 0
    }))
    .pipe(gulp.dest('build'));
});
```

srcディレクトリ以下をbabelでコンパイルし、buildディレクトリ以下に出力する記述です。
試しに実行したいのであらかじめsrcディレクトリ以下に適当なapp.jsxファイルを作っておきましょう。

あと、babelに `stage: 0` を渡しているのは「[ぼくのかんがえたさいきょうのElectron](http://qiita.com/Quramy/items/90d61ff37ca1b95a7f6d)」を参考にしました。
理由などの詳細はこの記事をご覧ください。

さて、実行です。
gulpコマンドを直接実行してもいいのですが、面倒なのでpackage.jsonにタスク実行コマンドを足しておきます。

```json:package.json
  "scripts": {
    "compile": "gulp compile",
  }
```

実行してみましょう。

```bash
$ npm run compile
```

実行後にbuildディレクトリ内を見てみると

```bash
build
└── app.js
```

ちゃんとコンパイルされたファイルが出来上がっていました。

# Livereload

ElectronでもLivereloadをしたいです。
やりたいこと。

* gulpでjsのコンパイル〜Electron起動を自動化
* jsファイルを監視し、変更があったら再コンパイル
* コンパイル後のファイルを監視し、変更があったらLivereload

変更を監視するためにelectron-connectをインストールします。
尚、こちらは[Quramyさん](http://qiita.com/Quramy)が作られております。

```bash
$ npm install electron-connect --save-dev
```

結果。

```js:gulpfile.js
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var electron = require('electron-connect').server.create();

var srcDir = 'src';
var libDir = 'build';

// jsファイルのコンパイル。
gulp.task('compile', function(){
  return gulp.src(srcDir + '/**/*.{js,jsx}')
    .pipe($.babel({
      stage: 0
    }))
    .pipe(gulp.dest(libDir));
});

// コンパイルしてElectron起動
gulp.task('start', ['compile'], function(){
  // electron開始
  electron.start();
  // ファイルが変更されたら再コンパイル
  gulp.watch(srcDir + '/**/*.{js,jsx}', ['compile']);
  // BrowserProcessが読み込むファイルが変更されたらRestart。
  gulp.watch(['main.js'], electron.restart);
  // RendererProcessが読み込むファイルが変更されたらReload。
  gulp.watch(['index.html', libDir + '/**/*.{html,js,css}'], electron.reload);
});
```

```html:index.html
<html>
  ...
  <script>require('electron-connect').client.create()</script>
  ...
</html>
```

そしてpackage.jsonを少し書き換えます。

```json:package.json
  "scripts": {
    "start": "gulp start"
  }
```

実行してみましょう。

```bash
$ npm run start
```

jsがコンパイルされ、Electronが立ち上がりましたか？
試しにjsファイルを変更してみてください。ElectronがLivereloadされるかと思います。
これで開発がとても便利になりました。

# ついでにJSHintも実行

ついでにJSHintも実行したいです。
ただ、JSHintは当然jsxファイルに対応していないので、代わりにJSXHintを使います。
本当はgulpを使って以下のように書きたかったのですが

```js:gulpfile.js
gulp.task('jshint', function () {
  return gulp.src('src/**/*.js')
    .pipe($.jsxhint())
    .pipe($.jsxhint.reporter('jshint-stylish')); // 結果をスタイリッシュに
});
```

まだgulp-jsxhintは使えないようで動きませんでした。
仕方ないのでgulpではなく通常のコマンドで動かすようにします。
まずは通常のjsxhintとjshint-stylishをインストール。

```bash
$ npm install jsxhint --save-dev
$ npm install jshint-stylish --save-dev
```

そしてpackage.jsonに以下の記述を足します。

```json:package.json
  "scripts": {
    "start": "gulp start",
    "test": "jsxhint --reporter node_modules/jshint-stylish/index.js 'src/**/*.js'"
  }
```

実行してみます。

```bash
$ npm run test

...

No problems
```

出来ました。
今後はtestを走らせたらJestやjscs等も実行されるようにしたいです。


# ついでにアプリのパッケージングも登録しておく

ついでに、アプリのパッケージングコマンドも登録しておくと楽でしょう。
僕は「package」というタスクでこんな感じにしてます。

```json:package.json
  "scripts": {
    "start": "gulp start",
    "package": "electron-packager . sample --platform=darwin --arch=x64 --version=0.30.0 --icon=images/icon.icns --prune --overwrite",
    "test": "jsxhint --reporter node_modules/jshint-stylish/index.js 'src/**/*.js'"
  }
```

実行してみます。

```bash
$ npm run package
```

パッケージングされたアプリが出来上がりました。
上記だとプロジェクトディレクトリ内にパッケージング後のディレクトリが出来てしまうので、gitignore推奨です。


# まとめ

Electronの開発に本格的に入る前に、開発環境を整えてみました。
gulpは始めて触ってみましたが、なかなか簡単に書けて良い感じでした。