思い立ったが吉日ということで、プロジェクトのモジュール管理をRequire.jsからBrowserifyへと移行し、その直後にWebpackに移行しました。もうちょっと考えてツールを選ぼうと思います。
さて、Require.jsからBrowserifyへ変えた理由は、シンタックスをCommonJS的に書けるようになって、全体がシンプルになるから、という理由でしたが、BrowserifyからWebpackへの移行は、もうちょっと切ない理由での移行になりました。
Webpackとは
ドキュメントも若干わかりづらいですが充実しており、基本的にここだけで必要な情報はほとんど得られます。
なのでこちらをどうぞ・・・じゃさすがにあれなので、ドキュメントに書いてある、作られた動機などを若干紹介します。
- 今はモジュールシステムがいろいろある
- CommonJS
- AMD
-
<script>
タグ - ES6 Module
- ほかいろいろ
- それらのモジュールにはPros/Consがそれぞれ存在するので、適切なものを利用したい
- Webでは、JavaScript以外にもCSSとか画像とかいろいろなものが利用される
- それらも全部まとめたい
- CommonJSとかで動的な読み込みができないの、たまに辛いよね
こんな感じの動機から、Webpackは作られたようです。
Webpackの特徴としては、
- コード分割
- requireの使い方で、AMDのような非同期のロードもサポート
- Loaderという読み込み時に適用するプラグイン
- require時に変数が入っていてもパースできるような、賢いパース
- Pluginによる拡張
という感じで、Browserifyとの一番の違いは、Browserifyが 単一ファイル を作成するのに特化していたのと比較して、Webpackは 複数ファイルを出力すること を念頭に置いている点だと思います。
私が今携わっているプロジェクトでは、複数のエントリーポイントがあり、それぞれが相当量のJavaScriptやらを利用しているため、それぞれのエントリーポイント別にbundleさせたいのです。
Browserifyでもやろうと思えばできましたが、結構面倒な点などがありました。
Webpack移行のポイント
Webpackへ移行するのは、すでにBrowserifyを利用しているなら、基本的に設定をちょっと変えれば、基本的には動作すると思います。が、いくつか両方に同じ名前の設定があるけど意味が違ったり、Browserifyでやっていたけどどうやるの?というような設定がありました。
externals
Browserifyでは、依存を追い出して利用するためにexternalsという設定を利用していました。
Webpackでも同名の設定があるのですが、若干意味が変わってしまい、Browserifyと同じようには利用できません。
Browserifyのexternalと同じように、共通する依存を分割する際にはCommonChunkPluginというものを利用する必要があります。
Sourcemap
ドキュメントにも書いてありますが、SourcemapはBrowserifyと違って複数の種類があります。
これがだいぶ注意なのですが、私の現在の環境では、かなりメモリがかつかつな状態でやっているのですが(常時90%オーバー)、Sourcemapを有効にすると、Browserifyと比較して、ビルド時にかなりのメモリを消費します。
プロジェクトで全然違った値になると思いますが、Sourcemapあり・なしのビルドしたときの、メモリ消費値を参考程度にあげておきます。
この値は、以下の条件ではかったものです。
- Vagrant上のCentOS
- メモリは768MB
- Bundle対象のJavaScriptファイルは大体40k stepくらい
- jQuery、jQuery UI、Backbone、Backbone.Marionetteを利用
では実測値です。
- Sourcemapなし
- 23〜6%
- eval
- 45〜50%
- source-map
- 75〜80%
- inline-source-map
- 50〜60%
- eval-source-map
- 50〜55%
みてわかる通り、結構なメモリを食います。source-mapは別ファイル、それ以外は生成したファイルに埋め込む形です。
ただし、デバッグ用途として利用するのであれば、inline-source-mapかsource-mapがオススメです。Chromeで(割と)快適にデバッグできます。
watchとcache
webpackのCLIを実行すると、自動的にキャッシュが有効になりますが、gulpとかgrunt経由で実行するときは、明示的に設定を有効にしないとキャッシュされません。
Polymerを使っている場合
ほとんどないとは思いますが、Polymerを利用していて、Polymerにもrequireなどを導入している場合、先にvulcanizeしてから実行する、など若干注意する必要があります。
それ以外は、複数出力可能という点で、Webpackの方がPolymerのVulcanizeされたJavaScriptをまとめやすい印象です。
それでもWebpackを選んだ理由
プロジェクトのデプロイをすべて自動化しようとしていたときに、Jenkinsのサーバー(m1.small)でBrowserifyのビルドをさせてみたところ、なんと20分くらいかかってしまいました。
ローカルのVagrant上でも、一回のビルドで3〜4分かかってしまっていたので(watchした場合、初回以外は高速です)、もしかしたらWebpackだったら早くなるのでは?ということでやってみたました。
結果としては、
- 一回(もしくはwatchの初回)のビルド時間
- Browserify => 3〜4分
- Webpack => 14〜16秒(!)
と、劇的に変わりました。ただし、Sourcemapを出力すると、相応の時間がかかるようになるため、Sourcemapを出力した場合は、大体Browserifyの半分くらいの時間になります。
この速度の優位性で私はWebpackにしたといっても過言ではありません。メモリがより潤沢にある環境ならば、devserverなどを導入してさらに効率よく開発することも可能でしょう。
(残念ながら私の環境はdevserverが利用できないので利用していませんが・・・)
Webpackにするなら今がチャンスかも
最近にわかに注目されてきていて、日本語記事もチラホラ見かけます。後Instagramとかが利用していて、利用で得られたtipsをgithub上で公開していたりしますので、みると非常に参考になります。
小規模からでも、モジュール化することによるメリットは大きいはず、というよりももはやモジュール化しないと破綻一直線なので、とりあえずでもいいので導入してみてはどうでしょうか。