Edited at

BrowserifyからWebpackへの移行時の注意点

More than 1 year has passed since last update.

思い立ったが吉日ということで、プロジェクトのモジュール管理をRequire.jsからBrowserifyへと移行し、その直後にWebpackに移行しました。もうちょっと考えてツールを選ぼうと思います。

さて、Require.jsからBrowserifyへ変えた理由は、シンタックスをCommonJS的に書けるようになって、全体がシンプルになるから、という理由でしたが、BrowserifyからWebpackへの移行は、もうちょっと切ない理由での移行になりました。


Webpackとは

http://webpack.github.io

ドキュメントも若干わかりづらいですが充実しており、基本的にここだけで必要な情報はほとんど得られます。

なのでこちらをどうぞ・・・じゃさすがにあれなので、ドキュメントに書いてある、作られた動機などを若干紹介します。


  • 今はモジュールシステムがいろいろある


    • 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上で公開していたりしますので、みると非常に参考になります。

小規模からでも、モジュール化することによるメリットは大きいはず、というよりももはやモジュール化しないと破綻一直線なので、とりあえずでもいいので導入してみてはどうでしょうか。