Gulpに頼らない！CLIで作るフロントエンド開発環境

## はじめに

今日はクライアントサイドWebアプリケーションの開発環境構築について書きたいと思います。

昨今、HTML, JS, CSSを駆使したWebアプリ開発の場においても、タスクランナーの導入は当たり前となってきました。

僕も日頃の業務ではフロントエンド用のタスクランナーとしてgulpを使っています。
gulpについては好きなところも嫌いなところもありますが、チームで仕事をする上では何らかのタスクランナーとビルドスクリプトの存在が欠かせないのは否定しません。
しかし、個人的に新しいフレームワークをちょっと勉強したいときにGruntやgulpのスクリプトをゼロから作成するのは、正直言って心が折れます。
[Yeoman](http://yeoman.io/generators/)や[SlushJS](http://slushjs.github.io/)でジェネレータを探すのも手ですが、自分の好みのフレームワーク、トランスパイラがセットで提供されないケースもしばしばです。
そうなると、結局自分でgulpfile.jsを読み解いた上で書き直す必要が出てきます。下手すると1からgulpfileを起こすよりも、他人が書いた物を理解する分だけ手間がかかることもあります。

そこで最近では、自分しか使わない勉強用のプロジェクトについては、gulpは使わずにCLIのみで済ませるようにしています。
ここでいうCLIとは`babel` や、`tsc`, `node-sass`といったコマンドを直接実行するという意味です。

勉強用プロジェクトでもっとも欲しくなるのは、`gulp.watch('src/**/*.ts', ['compile:typescript']);` のような「ソースのwatch とファイル変換」ですが、調べてみると、大概のツールにはCLI自体に`--watch` のようなオプションを持っていることが分かります。

今回はgulpを使わずにCLIだけで トランスパイル 〜 bundle 〜 LiveReloadを作る手順を紹介します。
コマンド名さえ覚えておけば、`--help` を付けて叩けば細かいオプションはその場で確認できるため、慣れてしまえばgulpfile.jsを書くよりもスピーディに開発環境を構築できると思います。

## TypeScript
まずはJavaScriptのトランスパイラ周りから。
[TypeScript](http://www.typescriptlang.org/#Download) は静的な型付け機能をもったJavaScriptのSuper Setです。

```sh:install
npm install -g typescript
```

コマンドラインから色々引数を与えることもできますが、 CLI自体に設定ファイルの雛形生成機能があります。
`tsc --init` を実行するとtsconfig.jsonが生成されるので、これを好みに書き換えるのが一番楽です。typoもしづらいですし。

```json:tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": true,
        "outDir": "built",
        "rootDir": "src",
        "sourceMap": false
    },
    "exclude": [
        "node_modules"
    ]
}
```

一度、tsconfig.jsonを作っておけば、 `tsc -w` とするだけで、`**/*.ts` を変更するたびに、`built` の配下に.jsファイルを吐き出し続けてくれるようになります。

## babel

[babel](https://babel.io) もJavaScriptのトランスパイラとして人気のツールです。

```sh:install
npm -g install babel-cli
```

`-w`または`--watch` オプションでソースファイルの変更を検知して都度トランスパイルしてくれます。

```sh:ファイル検知
babel -d dist -w src/**/*.js
```

ただ、babelの場合, 実際の変換処理を担っているbabel pluginをまとめたpresetが無いと殆ど何も出来ません。
例えば、ECMA 6thとReact JSXを使いたい場合、対応するpresetのinstallと`--presets` の指定が必要となります。

```sh:babelのpresetを利用
npm install babel-preset-es2015 babel-preset-react --save-dev
babel -d dist -w src/**/*.js --presets es2015,react
```

presetはグローバルインストールしても意味がないので、install時に `-g` は付けていません。

## browserify
[browserify](http://browserify.org/)はcommonjsの`require` を片っ端からかき集めて依存関係を解決した上で、単一の.js ファイルを作成するツールです。

以下のように、app.jsとそれを呼び出すbootstrap.jsが存在していたとしましょう。

```js:built/bootstrap.js
console.log(require('./app'));
```

```js:built/app.js
module.exports = 'Hello, world';
```

```sh:browserifyのinstallと実行
npm -g install browserify
browserify built/bootstrap.js -o bundle.js
```

出力されたbundle.jsをブラウザで読み込むと、コンソールに`'Hello, world'`と出力されます。

browserify自体はwatchオプションを持っていませんが、代わりに[watchify](https://github.com/substack/watchify)というツールが存在します。

```sh:watchifyのinstallと実行
npm -g install watchify
watchify built/bootstrap.js -o bundle.js -v
```

`-v`(`--verbose`)オプションが無いと、コンソールに一切の出力がなされず不安になってしまうので、付けておくことをオススメします。

browserify, watchifyともに `-p babelify` のようにトランスパイラをpluginとして差し込むことも出来ます。
しかし、今回のエントリのようにCLIベースで組み立てるときは、トランスパイラはトランスパイラのCLI, browserify(watchify)は変換された.jsを元にbundle.jsを作るだけ、と分割して考えた方が楽と思っています。
中間ファイルの生成回数は増えるものの、各コマンドの叩き方がシンプルです。コマンドラインベースで物を考えるときは、1つのコマンドに作業を押し付けない方が後々で忘れにくいので。

## Sass

ここまでJavaScriptの話でした。折角なので、CSSもCLIツールでwatchしてみます。

lib-sassのNode.jsラッパーである [node-sass](https://github.com/sass/node-sass)で.scssファイルを.cssへ変換しましょう。

```sh:install
npm -g install node-sass
```

```sh:node-sassの実行(sassディレクトリ配下を再帰的に監視)
node-sass sass/app.scss -w sass -r -o css
```

僕は普段、そんなに大量のmixinライブラリを使うようなことはしませんが、compassを少し使いたいぐらいのことであれば、`npm install` と node-sassの`--include-path` オプションで充分対応できます。

```sh:compassのmixin付
npm install compass-mixins
node-sass sass/app.scss -w sass -r -o css --include-path node_modules/compass-mixins/lib
```

```scss:sass/app.scss
@import 'compass';
// :
```

## LiveReload

ここまでで、Alt-JS, Alt-CSSについて、ソースをwatchしながらトランスパイルしてbundle.jsやapp.cssを作ることが出来るようになりました。

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>My App</title>
    <link rel="stylesheet" href="/css/app.css">
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>
```

あとはこれらが変更された際に自動的にリロード、すなわちLiveReload機能を持たせたWebサーバを用意します。
LiveReload機能付のWebサーバといえば、[browser-sync](https://www.browsersync.io/) です。

```sh:install
npm install -g browser-sync
```

下記のように`--files` オプションに変更検知対象のファイルを列挙していけば、これらが変更された際に自動的にReloadしてくれます。

```sh:browser-syncの起動
browser-sync start --server --files index.html --files bundle.js --files css/app.css
```

ちなみに `browser-sync init` とすると、`bs-config.js` というファイル名で設定ファイルの雛形を吐き出してくれます。
このbs-config.jsをお好みで編集したのち、以下のようにCLIを実行するのも便利です。

```sh:configファイルを利用した起動
browser-sync start --config bs-config.js
```

## Put it all together
ここまでで、AltJS, AltCSSのトランスパイル, WebServerのLiveReloadをCLIで実現できるようになりました。
既にあなたのターミナルでは、watch系のプロセスが複数立ち上がっていることでしょう。
でも、毎回叩くの面倒ですよね？

折角なので、コマンド一発で起動できるようにしてみましょう。[node-foreman](https://github.com/strongloop/node-foreman) というツールを利用します。foremanはプロセス管理を行うためのRuby製ツールで、node-foremanはこいつのnode.jsクローンです。

```sh:install
npm -g install foreman
```

続いて`Procfile`という名前のファイルを作成し、これまでに叩いてきたCLIのwatch系コマンドを`キー: コマンド`の形式で列挙していきます。
キーは分かりやすい名前であれば何でも構いません。

```Procfile:Procfile
typescript: tsc -w
bundle: watchify built/bootstrap.js -o bundle.js -v
sass: node-sass sass/app.scss -w sass -r -o css --include-path node_modules/compass-mixins/lib
livereload: browser-sync start --server --files index.html --files bundle.js --files css/app.css
```

最後に`nf start` コマンドを実行すれば、上記で列挙したプロセスが全て立ち上がってくれます。

```sh:全部まとめて起動する
nf start
```

## おわりに
今回のエントリでは`-w `(`--watch`) オプションのあるCLIだけで開発環境を作ってみました。
TypeScript, Babel, Sassのコンパイル, browserifyによるbundle.jsの作成, Browser Syncでのライブリロード等を紹介しました。

CLIベースなので、シェルスクリプトと組み合わせれば自分用のジェネレータを作るのも簡単です。
実際に今回紹介した方法でangular2 betaのジェネレータを作ってみました。[https://gist.github.com/Quramy/bc0a2ad00595e918b825](https://gist.github.com/Quramy/bc0a2ad00595e918b825)

冒頭でも述べた通り、常にCLIが最良の選択肢と言いたい訳ではありませんが、「サクッと望みのフレームワークが動く」という目的を達成するだけであれば、CLIベースで組み立てる方が短時間で作成できます。
環境構築手段の1つとして、オプションに入れてみては如何でしょうか。