チーム展開と保守性を考慮したクロスプラットフォームHTML5ビルドシステムの考察

#概要
本稿は、HTML5を効率的に開発する環境をマルチプラットフォームで素早く展開する方法について考えて試作したものの備忘録です。後述するツール達は、執筆時点で選定した技術ですが、既に古くなったものもあると思います。Web開発の技術は非常に早いペースで世代交代しているため実際に利用する際には、選定技術の見直しやバージョンアップを行ってください。なお本稿は、所属会社の自習課題として書き進めたものですが発表するアテが無くなってしまった為、こちらに投稿します。
##構築方針
現在私の所属している会社の開発プラットフォームは、Windowsのみという状況になっています。一方ターゲットとなるプラットフォームは、モバイルアプリケーションやWebへ移りつつあります。ターゲットとなるプラットフォームがWindowsから移りつつあるため開発環境もクロスプラットフォームな方が良いと考えました。また、個人的にメインで利用しているOSは、Linux(Ubuntu)なので、自宅で作業を進めることも考えて、クロスプラットフォームを重視した構成としました。(サブ環境にWindows使ってますけどね)ただ、単純に仮想環境に開発環境を構築して、ホストからリモート操作するだけだと新奇性がありませんので、テキストエディタは使い慣れたものが利用できることを重視しました。
###クロスプラットフォーム性の確保
クロスプラットフォームを実現する基盤技術として、Vagrant+VirtualBoxを利用します。Vagrantは仮想環境を制御するツールですので、実質的には、VirtualBoxを使った仮想環境で開発ツールを実行することとなります。Vagrantについて知らない方が読まれると「結局仮想環境を使ってクロスプラットフォームを実現するだけか」と思われるかも知れませんが、VagrantとVirtualBoxを組み合わせることによって大きく使い勝手が向上します。本稿で目指すビルドシステムは、コンパイル環境のみを仮想環境化するものでありエディタについては、各ホストのネイティブなツールの利用を想定しています。
###簡便な配布
ビルド環境の配布は、boxファイルによって行います。boxファイルは、Vagrantの仮想環境エクスポートファイルで、boxファイルをインポートすれば、簡単に仮想環境を複製することができます。一度boxファイルを取り込んでしまえば、2度目の仮想環境構築は非常に高速に行えます。仮想環境としてワンパッケージで配布することによって、プロジェクトの立ち上げや人員の追加がスムーズになります。
###更新のし易さ
Vagrantは、手を加えた仮想環境を簡単に、boxファイルにすることができます。案件ごとにカスタマイズした仮想環境をboxとしてパッケージ化すれば、新しいツールや更新バージョンに簡単に対応することができます。
###ネイティブツールの利用
本稿でパッケージ化するのは、ビルド部分のみです。コードを記述する部分は、ネイティブ環境のエディタを利用することができます。
#構築技術説明
##VirtualBox
![vbox_logo2_gradient.png](https://qiita-image-store.s3.amazonaws.com/0/7839/13a4cd1f-93e7-0850-a8fa-88a07841e2eb.png)
Oracleによって開発されているOSSのホスト型仮想化ソフトです。ゲストOSがx86,x64アーキテクチャであれば基本的に動作します。本稿では、Ubuntu14.04 ServerをゲストOSとして走らせる仮想化環境として利用します。
[Oracle VM VirtualBox Dwonload](http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html?ssSourceSiteId=otnjp)

##Vagrant
![Vagrant.png](https://qiita-image-store.s3.amazonaws.com/0/7839/ca6de978-de06-0525-5ebc-dadf8c00d8b3.png)
Vagrantは、一言で言うと仮想化ソフトの制御ツールです。デフォルトでVirtualBoxに対応していますが、VirtualBox専用のツールという訳ではありません。仮想環境の設定が自動化されており仮想環境を作ったり壊したりが簡単にできるようになっています。Vagrantの仮想化ファイルであるboxは作成ルールが決められており、どのboxを利用しても迷いが少ないように気が配られています。本稿のビルドシステムでは、ホストOSとゲストOSの間でフォルダ共有を行い使い慣れたエディタを利用できるようにします。
[DOWNLOAD VAGRANT](https://www.vagrantup.com/downloads.html)

開発環境構築には、筆者が使い慣れているUbuntu serverの最新LTS(14.04)を使用します。
[Official Ubuntu 14.04 daily Cloud Image amd64](https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box)

```prompt:
> vagrant box add ubuntu14.04 https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
```
##io.js(node.js)
![1.0.0.png](https://qiita-image-store.s3.amazonaws.com/0/7839/74cc6680-2e16-a99e-b236-757ed7bb2ed2.png)
io.jsは、node.jsからforkしたOSSツールです。node.jsとの互換性を保ちつつ最新のChrome V8エンジンを採用するなど高速化が図られています。io.js独自の機能を利用するつもりは無いためnode.jsを利用しても問題はありません。
io.jsをインストールするためにnodebrew(node.jsバージョン管理ツール)をインストールします。nodebrewは、io.jsに対応しています。（※最近node.jsと仲直りしたらしくio.jsはnode.jsへ統合されるらしいです）

```bash:
$ wget git.io/nodebrew
$ perl nodebrew setup
```
インストールされたnodebrewへのPATHを.profileへ登録します。viを使って最終行へ追加します。

```bash:
$ vi ~/.profile
```
追加するパス

```bash:
  export PATH=$HOME/.nodebrew/current/bin:$PATH
```

再起動せずに、PATHを有効化します。

```bash:
$ source ~/.profile
```
nodebrewを利用して、最新バージョンのio.jsをインストールします。

```bash:
$ nodebrew install-binary io@latest
$ nodebrew use io@latest
$ node -v
v1.1.0
```
##Gulp.js
![gulp.png](https://qiita-image-store.s3.amazonaws.com/0/7839/4f62d667-771c-08ce-e801-f3dc2f38aa89.png)
gulp.jsは、タスクランナーと呼ばれるツールで、node.jsで動作するmakeやantのようなツールです。grunt.jsというタスクランナーが先行して普及していましたが、gulp.jsはタスクを非同期に実行できるなど高速に処理が可能になっています。本稿で構築するビルドシステムでは、ソースファイルを監視して、HTML,CSS,Javascriptを自動コンパイルします。

```bash:
$ npm install --global gulp
$ npm install --save-dev gulp
$ gulp -v
[03:23:00] CLI version 3.8.11
[03:23:00] Local version 3.8.11
```

```bash:
$ npm install gulp-plumber --save-dev
$ npm install del --save-dev
$ npm install browser-sync --save-dev
$ npm install gulp-pleeease --save-dev
$ npm install gulp-concat --save-dev
```
##Jade
![jade-template-engine-nodejs-express-web-framework.png](https://qiita-image-store.s3.amazonaws.com/0/7839/2e326364-8144-9cb9-ba5f-9b95045889ac.png)
Jadeは、HTMLテンプレートエンジンです。軽量マークアップ言語であるHamlに影響を受けておりHTMLを部品として管理して生成することが可能です。Webサイトは複数の部品の組み合わせで構成されてるので静的ページを大量に作るには効率的です。ifやwhileの関数も使えるためページ毎の差異や繰り返しにも柔軟に対応することができます。

```bash:
$ npm install gulp-jade --save-dev
```
##Sass
![node.png](https://qiita-image-store.s3.amazonaws.com/0/7839/0f08596e-8d91-de9e-0c90-83709ef40016.png)
はじめgulp-sassを使用するつもりで構築を行ったのですが、io.jsとの相性が悪いらしく私の能力ではエラーを回避できませんでした。sassは元々Rubyのコードで書かれておりgulp-sassは、node.jsへ移植されたコードを利用しているようです。そのためio.jsとの非互換部分に引っかかってしまうのでしょう。gulp.jsには、rubyをそのまま使うgulp-ruby-sassというプラグインも有りコンパイル速度は遅いものの精度の高いコンパイルが出来るようです。今回は、gulp-ruby-sassを使うことにしました。

```bash:
$ npm install gulp-ruby-sass --save-dev
$ sudo gem install sass
```
##TypeScript
![typescript2.jpg](https://qiita-image-store.s3.amazonaws.com/0/7839/203c6496-a88c-346f-0b5e-c2ade0d8e9aa.jpeg)
技術的な選定の中で、TypeScriptの選定が最も好みを反映したものかも知れません。altJSで抜きに出て普及したものはまだ存在しておらず一長一短を理解して使用する状態だと思います。altJSは、ECMAScript6が普及するまでの繋ぎという位置づけなのですが、ECMAScriptを生のママ使うという時代が来るのかは未知数な気がします。TypeScriptの長所は、ECMAScript6において機能実装が期待されている機能を先取りして実装している点です。他のaltJSが新しく作成した言語からECMAScriptへのコンバートを主眼に置いているのに比べTypeScriptの言語仕様はECMAScript6(の予想)からECMAScriptへのコンバートというコンセプトで作られています。ECMAScript6は、ECMAScriptの拡張であるためTypeScriptからコンバートされたECMAScriptは、元のコードと似ても似つかないコードにはならないようです。コンセプト通りであれば、ECMAScript6の実装度が進めば、TypeScriptのラッパーは薄くなっていき消滅する運命にあるのでしょうが、ECMAScript7の言語仕様なども取り込んでいき、先進仕様と現行実装とのギャップを埋める言語として存続していくのだと思われます。

```bash:
$ npm install gulp-typescript --save-dev
$ npm install gulp-concat --save-dev

```



#ビルド環境構築方法
#ビルド環境展開方法
##VirtualBoxのインストール
##Vagrantのインストール
##boxの追加
vagrantへboxファイルを登録します。登録は一度行えば、繰り返し使い回すことが可能です。

```prompt:
> vagrant box add webbuildsys ./webbuildsys-v1.0.0.box
```
##仮想環境の初期化
プロジェクトフォルダへVagrantfileを配置します。テンプレートとして配布されているファイルをコピーするするのが簡単ですが、下記のコマンドを実行してから書き換えて用意することもできます。

```prompt:
> vagrant init ubuntu14.04
```
Vagrantfileファイルの雛形が生成されるので、テキストエディタで下記のように書き換えます。

```vagrant:Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    config.vm.box = "ubuntu14.04"
    config.vm.network "private_network", ip: "192.168.33.10"
    config.vm.synced_folder "./project", "/home/vagrant/build/project", create: true, owner: "vagrant", group: "vagrant", mount_options: ["dmode=777", "fmode=777"]
    config.vm.provider "virtualbox" do |vb|
    end
end
```

##仮想環境の実行
ビルドシステムを起動するには、下記のコマンドを実行します。

```prompt:
> vagrant up
```

ビルドシステムが起動するとVagrantfileがあるフォルダに、./projectフォルダが作成されます。このフォルダはビルドシステムの監視対象になります。 *.jade, *.scss, *.tsをファイルを更新すると更新を検知して自動的にビルドされます。コンパイルするためにコマンドを叩く必要はありません。
##フォルダ構成
| /          | 第二階層     | 第三階層      | 備考         |
|:-----------|:------------|:-------------|:-------------|
| .vagrant/  |             |              |              |
| Vagrantfile/|            |              |              |
| project/   |             |              |              |
|            | .git/       |              | バージョン管理は、この階層で行う |
|            | .gitignore  |              |              |
|            | dest/       |              |              |
|            |             | index.html   |              |
|            |             | page/        | *.html       |
|            |             | js/          | *.js         |
|            |             | css/         | style.css    |
|            | src/        |              |              |
|            |             | index.jade   |              |
|            |             | jade/        | *.jade       |
|            |             | ts/          | *.ts         |
|            |             | scss/        | *.scss       |

##コンテンツの確認方法
ブラウザから下記のアドレスへ接続すれば、ビルドされたコンテンツを確認することができます。ファイルを更新するとブラウザが自動リロードされます。
[http://192.168.33.10:3000](http://192.168.33.10:3000)
[BrowserSync UI](http://192.168.33.10:3001)

##仮想環境の終了
ビルドシステムを終了させるには、下記のコマンドを実行します。

```prompt:
> vagrant halt
```
#保守
##仮想環境へのログイン
vagrantのboxファイルは、必ずユーザーとパスワードが"vagrant"に設定されています。windowsの場合は、sshコマンドが使えないのでputtyなどターミナルソフトを使って接続をしてください。macやlinuxでは下記のコマンドでログインできます。

```bash:
$ vagrant ssh
```

##boxファイルの作成
案件の運営方針に合わせてビルドシステムをカスタマイズした場合には、下記のコマンドを使って派生boxファイルを作成してください。boxが作成できれば、案件メンバーへ展開することも保守案件として、開発環境を保持しておくことも容易になります。

```prompt:
> vagrant package --name webbuildsys-v1.0.1.box
```

##パッケージファイル
package.jsonは、下記のように設定されています。

```bash:package.json
{
  "name": "webbuilder",
  "version": "1.0.0",
  "description": "web build system",
  "main": "gulpfile.js",
  "dependencies": {
    "del": "^1.1.1",
    "gulp": "^3.8.11",
    "gulp-jade": "^0.11.0",
    "gulp-plumber": "^0.6.6"
  },
  "devDependencies": {
    "browser-sync": "^2.0.0-rc10"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "t-shibuya.",
  "license": "Apache 1.1"
}
```

##ビルド指示ファイル

```bash:gulpfile.js
'use strict';
var gulp = require('gulp');

var browserSync = require('browser-sync');
var reload = browserSync.reload;

var plumber = require('gulp-plumber');
var jade = require('gulp-jade');
var del = require('del');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
];
var pkg = require('./package.json');
var BANNER = [
  '@charset "utf-8";',
  '/**',
  ' * <%= pkg.name %> - <%= pkg.description %>',
  ' * @link <%= pkg.url %>',
  ' * @version v<%= pkg.version %>',
  ' * @Author <%= pkg.author %>',
  ' * @Author URI <%= pkg.author %>',
  ' */',
  ''
].join('\n');

gulp.task('default', function () {
    browserSync({
        notify: false,
        port: 3000,
        server: {
          baseDir: ['./project/dist/']
        }
    });
    gulp.watch(['./project/src/jade/*.jade','./project/src/jade/**/*.jade','src/project/jade/**/_*.jade'],['jade']);
});

gulp.task('jade', function () {
  gulp.src(['./project/src/jade/*.jade','project/src/jade/**/*.jade','!project/src/jade/**/_*.jade'])
    .pipe(plumber())
    .pipe(jade({
      pretty: true
    }))
    .pipe(gulp.dest('./project/dist/'))
    .on('end', reload);
});

gulp.task('clean', function(cb) {
  del(['./project/dist/**/*.html','./project/dist/**/*.css','./project/dist/**/*.xml'], cb);
});
```
#効果測定
実際に、静的なHTMLをJade化して、どのくらい省力化できる可能性があるのかを調べてみました。[EショップのPSDテンプレート](http://jp.freepik.com/index.php?goto=41&idd=693640&url=aHR0cDovL3dlYmRlc2lnbi1mcmVlYmllcy50dW1ibHIuY29tL3Bvc3QvNTQzMjA5MzY3MDEvZnJlZS1lc2hvcC1wc2QtdGVtcGxhdGU=)は、PSDデザインファイルだけではなくHTML/CSS/JSも用意されていたので、[HTMLをJade化してくれるサイト](http://html2jade.aaron-powell.com/)を使用して、Jadeファイルを作り手作業で、繰り返し処理を入れてみました。Jade初心者が作業しても半分以下に効率化することができました。記述量が少ないことが絶対的な指標では無いとは思いますが、制御文やパーツ化を駆使することができれば、効率よく開発できると考えられます。だだし、慣れとノウハウの蓄積は必要な気がします。

#Jade
|ファイル名   | オリジナル     |Jade変換＋繰り返し最適化| 縮小率         |
|:-----------|:------------|:-------------|:-------------|
|index.html  |14.9 kB (14,885 bytes)|7.4 kB (7,356 bytes)|49.4% |

-------------------

#問題点
##gulp.jsを起動
Vagrantを起動しただけでは、gulp.jsは実行されません。何か方法は有りそうなのですが、今のところゲストOSへターミナルでログインして実行するしかありません。開発者が使うので大丈夫かなとも思いますが、黒い画面恐怖症の人も居るので、何とかしたいところです。
##ビルドエラーの確認
ビルドでエラーが起きた場合に、コンソールにエラー内容が表示されるためターミナル画面で、確認する必要があります。Vagrantと同時に自動起動するようにできたら、エラーの確認をどうするのか、考えなければなりません。

#まとめ
仕事でWebの開発に携わって無いため実際の開発事情を汲み取れていない内容になっているかもしれませんが、Web開発を始めることがあったら今回調べた内容を流用して環境を構築しようと思ってます。