Herokuとwebpackでローカルサーバ不要のフロントエンド開発

この記事は[Heroku Advent Calendar 2015](http://qiita.com/advent-calendar/2015/heroku)の６日目の記事です。

もともとは、DataClipの応用的な活用を試みようと思ってたんだけど、~~すっかり忘れていた~~予定外に体壊したりしてやってる暇がなかったので、もう一個のネタについて書きます。

それは[webpack](https://webpack.github.io/)についてです。

## webpackとは
一言で言えばフロントエンドJSのbuildツールです。
複数のJSファイルをひとつのファイルにまとめてくれます。

といっても、ただ単に複数のファイルをコンカチしてるだけではありません。それぞれのファイルの名前空間は分かれており、requireを使ってmoduleベースの開発を行うことができるようになっています。
結合対象のファイルは自分で開発したファイルだけにとどまらず、JQueryやReact.jsなどのフレームワークも含むことができます。

また、驚いたことにデフォルトではCSSもJSの中に組み込まれます。
CSSもSASS等を用いて複数ファイルで定義することができますが、このコンパイル結果が**全部JavaScript化されて生成される、jsファイルの中に組み込まれる**のです！

あまりに、キモいので僕はPluginを使ってCSSは別ファイルに出力するように変更しちゃいましたが、まぁその辺は好みかと思います。

## webpackの良いところ
- requireが使える
- jQuery等の外部ファイルも一つにまとめてくれる
- Pluginを使ってjsx(React)やts(TypeScript)にも対応可能

といったところでしょうか、ライブラリの追加もnpmでインストールさえすれば、どこからでもrequireできるので、楽チンです。

実際のところ、最初に設定を行ってから約８ヶ月、ほとんど設定を変えずに開発できています。

## webpackのダメなところ
- documentが貧弱
- **コンパイルが遅い**

documentは日本語情報が少ないというは言わずもがなですが、公式のドキュメントもかなりアバウトな印象です。
ソース読まないとわからないところも多々ありましたが、そんなに巨大なプロダクトでもないので、怖れずソースを読んでみるのが吉です。
ちなみにPullRequestだしたら**無言でmerge**されたりもしたので、開発に関わっている人はかなり少ないような気もします。

問題なのは二つ目のコンパイルが遅いという点です。手元ではgrunt watchと組み合わせて関連するファイルが変更されたらリビルドするようになっていますが、これが数秒かかります。

これは、現在のプロジェクトではwebpackでReactやjQueryなどの外部ファイルもひとつにまとめるようになっていることが原因で、要するに巨大な外部ファイルを毎回コンパイルしているから遅いのです。

フロントエンド開発では文言をちょっと変えるだけ、とかの細かい修正も多々あるので、毎回数秒の待ち時間というのははっきり言ってやってられません。

## コンパイルの遅さを解決するwebpack-dev-server
そこで登場するのが[webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html)です。

webpack-dev-serverとはwebpackでのフロントエンド開発を支援する簡易webserverで以下の特徴を備えています。

- webpackの対象ファイルを監視し、変更が行われた場合に自動コンパイル
	- 差分コンパイルなので早い
	- mapファイルが生成されるので、ブラウザでのconsole.log出力で表示される行番号は各ファイルの行番号になる
- 変更検知時にブラウザを自動リロード
- **Proxyサーバ機能を備えている**ので、API等のサーバを必要とするURLの場合は別サーバにリクエストを転送することができる

これがどれほどに画期的なことかわかるでしょうか。。。

ReactやAngularを使ったSinglePageAppの開発では最初に表示するindex.htmlにはjs/cssのリンクだけを貼ってbody以下には何も記述しないのが普通です。

言い換えれば、index.htmlの生成にはサーバサイドの機能は不要で、静的なHTMLだけで間に合います。

つまり、index.htmlとwebpackで生成するjs/cssのみをwebpack-dev-serverから供給し、残りをHeroku等の開発サーバに転送するようにしておけば、フロントエンド開発者のローカルマシンにはサーバは不要になるわけです。

これは以下のような場面で特に役立ちます。

### 1、デザイナー、またはフロントエンド専任開発者の環境セットアップ
現在のプロジェクトではVagrant/Ansibleを用いて開発環境を自動で構築できるようになっていますが、それでもデザイナーにはかなりハードルが高い作業です。(Windowsマシンを使っていたらなおさらです。。。)
また、Vagrant内にDBやRedisがあっても、結局データがなければデザインは作れないので、そのデータをどのように作るかという課題も残ります。

このやり方の場合、フロントエンド開発者に必要なものは

- node.js
- npm
- Grunt(もちろんGulpでも良いし、必須ではない)

のみとなり、データ作成も他の開発者が支援できます。

### 2、サーバ・フロントエンド兼任開発
前述の通り、通常のwebpackのビルドは相当遅いので、フロントエンドとサーバサイドの両方を担当する開発者の場合であってもwebpack-dev-serverを使ってlocalの開発サーバにAPIをproxyするように設定します。

### 3、本番環境のデバッグ
**一番便利で一番伝えたいこと**はこれです。
アプリをリリースした後にはその本番環境でしか再現しないバグが発生することもありますが、その場合でもwebpack-dev-serverを本番環境に接続して、console.logをガンガン埋め込みつつ本番環境の実データを使って調査・修正を行うことができます。

正直、この一点のみでもwebpackを使う価値はあると思います。
今までなら「どうやってローカルで再現させよう。。。」というところからスタートしていたデバッグが、実データをそのまま使って行えるので非常に楽です。

以下に実際にプロジェクトで使っている、Gruntfileとindex.htmlを公開用に編集したものをアップしました。

https://gist.github.com/shunjikonishi/d5b814aa09f819da37ee

webpack以外の部分をガンガン削る修正をソラで行ったので、どこか間違っているかもしれませんが。。。(^^;;;
公式ドキュメントと合わせて見れば大体の内容はわかるはずです。

ポイントは

- Gruntタスクで接続するサーバを切り替えている
    - withLocal - ローカル開発サーバ
    - withDev - Herokuにある開発サーバ
    - withProd - 本番サーバ
- CSSはbuild時には分離しているがwebpack-dev-serverではbundle.jsに含めている
    - 記憶が定かではないが多分ExtractPluginがうまく動かなかった
  
といったところでしょうか。
それなりに調べて設定した内容ではありますが、半年以上前の設定なので今は変わっているところもあるかもしれません。(手元のwebpack-dev-serverのバージョンは1.10.1、最新は1.14.0。webpack本体のバージョンアップの速度はそれほど速くありませんが、dev-severはかなり速い印象)

## まとめ
以上、Heroku Advent Calendar 6日目でした。
なお、途中で気がついた人もいるかと思いますが、この話は実はHeroku全然関係なくAWSでもAzureでも使えます。(^^v