webpackの基礎知識webpackはモジュールバンドラと呼ばれるツールのひとつです。シリーズ第一回は、webpackがどのような問題を解決しようとして生まれたツールなのか、特徴的な機能にはどのようなものがあるかを解説します。智朗フロントエンド・エンジニア次回このシリーズの記事一覧をみる目次webpackが開発された経緯webpack以外のモジュールシステムの特徴webpack以外のモジュールシステムが解決できない問題webpackが提供するハイブリッドなモジュールシステムJavaScriptだけを対象にしないモジュールシステムまとめ2017年現在、フロントエンドの開発に携わっている方であれば、webpackの名前を聞いたことがない、という方はいないのではないでしょうか。webpackは最新のJavaScriptアプリケーション用のモジュールバンドラで、アプリケーションにおけるモジュールの依存関係を解析して1つまたは複数のパッケージにバンドルします。競合としてrollup.jsやFuseBoxがあるものの、webpackは今では多くのスポンサーやコントリビューターを獲得し、これらライバルを抑えてデファクト・スタンダードの地位を築いていると言えるでしょう。一方で、webpackの評価については「設定の仕方がわからない」「できれば触りたくない」といった声を耳にすることもあります。どちらかと言うとネガティブな要因のほうが多いように感じています。webpackの設定が複雑でわかりにくいことは否定しませんが、まずはなぜwebpackが必要になったかの経緯を知ってみるのもいいかもしれません。全部の機能を使いこなそうとしないで、基本的な機能から理解していけば、webpackの見方もずいぶん変わるのではないかと筆者は考えています。webpackの使い方を学ぶ前に、まずはwebpackが開発された経緯を追ってみましょう。webpackとmotivationに目を通すのが良いと思います。ここに記されているwebpackが開発されることになった経緯や、webpackが目指す目標について噛み砕いて説明します。最近では、AngularやVue.jsの開発に使用されるCLIツールによってwebpackが隠蔽され、webpackの設定をしなくても開発が続けられる環境が整ってきています。これらCLIツールを使うことで開発効率を向上させることができるプロジェクトでは積極的に活用していくことをおすすめします。その上でCLIツールを介してwebpackが裏でどのようなことをしているのか理解しておくと良いでしょう。CLIvue-cliwebpackが開発された経緯webpack以前には、BrowserifyとGruntやgulpを組み合わせたモジュールシステムの仕組みが、もっともポピュラーであったと思います。明言はされていませんが、おそらくwebpackの作者も以前はこれらのツールを使用していたのではないかと考えられます。これら既存のモジュールシステムではいけなかったのでしょうか。結論から言ってしまえば、webpack以前のモジュールシステムが大規模なシステムに適していなかったということに尽きます。webpack以前のGrunt、gulpやBrowserifyは、基本的にはすべてのモジュールを1つのファイルに結合して出力するように設計されています。プロジェクト全体でapp.jsやbundle.jsといった容量の大きいファイルを1つだけ出力していたという読者も多いのではないでしょうか。昨今ではフロントエンドの担う役割は年々増大しており、それに伴ってフロントエンドの占めるコードの割合も増大しているので、それを1つのファイルに落とし込むとなると、ファイルサイズはかなりのものになります。これがページ数が何百ページにも及ぶ大規模なアプリケーションだった場合、ファイルサイズは数十MB、もしかしたら数百MBということにもなりかねません。そのファイルを初回アクセス時にユーザーに読み込ませるとなると、無関係のコードも含まれる1つのファイルの読み込みを、ユーザーは延々と待たされることになります。使用されない機能のちょっとした変更であっても、プロジェクト全体の処理が含まれるファイルが更新されることになるため、キャッシュが非効率になるという問題もあります。理想はアクセスしたページに依存関係のあるコードだけが含まれるファイルが読み込まれ、初期ローディングが必要最小限に抑えられることでしょう。これらの問題を解決するために既存のモジュール・バンドラーを拡張することも試みられたそうですが、目的を果たすことができずwebpackを開発するに至ったことが記されています。先ほど説明した問題を解決するためにwebpackがどのようなアプローチを取るのかを説明する前に、その他のモジュールシステムについてそれぞれの利点と欠点を確認しておきましょう。src="control2.js"></script><script>タグの使用は、Node.jsの登場以前から、モジュールベースのコードを実現するために取られたアプローチです。モジュールは、グローバルオブジェクト(window)へのインタフェースをエクスポートし、グローバルオブジェクトを介して依存関係にアクセスします。require('./foo');同期requireメソッドで依存関係を読み込み、エクスポートされているインターフェースを取得します。モジュール側はexportオブジェクトへプロパティを追加したり、module.exportsに値を設定することでエクスポートします。Node.jsやBrowserifyでこの形式が使用されています。Hoge();});ネットワークを介するブラウザに対してCommonJSの形式による同期requireでは解決できない問題を、非同期のバージョンとして解決が図られている形式です。RequireJSでこの形式が使用されています。2015では、モジュールシステムが言語構成の一部としてJavaScriptに追加されました。CommonJSやAMDなど、複数のシステムがある背景には、JavaScriptの標準であるECMAScriptにそもそもモジュールの仕組みがなかったことにあります。2015でついに、このような標準のモジュールシステムが導入されました。modulesの詳細については、CodeGridの次のシリーズも参考にしてください。modulesを使用する場合は、コネクション数の問題からHTTP/2と併用することが大前提となります。HTTP/2と併用できる状況であっても、サードパーティのライブラリを使用するとなると、./node_modules/のモジュールに対して大量、かつ深いネストの依存関係を持つことになります。Modulesの資料によると、現状ではモジュールが数百におよぶ場合、またはネストの深度が5以上の場合は、バンドルすることが強く推奨されています。webpack以外のモジュールシステムが解決できない問題webpack以外のモジュールシステムについて、それぞれの特徴や役割、利点と欠点があることを確認しました。ここで注目したいのは、これらの特徴を用途に合わせて使い分けることが「できない」という点です。モジュールシステムが1種類しか使えないということは、たとえば、通常は同期モジュール読み込みのシンプルな書式で記述したいが、ある特定の機能(ページ)ではモジュールの非同期読み込みをしたいといった状況に応じた使い分けができないという問題があります。冒頭で触れましたがファイルのバンドルをどう扱うのかという問題があります。ファイルを分ければ、必要なものだけをブラウザが読み込めてよいという点もありますが、その一方で、リクエスト数が増えることは否めません。逆に、ファイルをまとめればリクエスト数は減りますが、無駄なコードを読み込んでしまったり、ファイル容量や実行にコストがかかります。このような、あちらを立てればこちらが立たずな状況が、これまでの「バンドルする・しない」という選択にも、バンドルするツール側にも課題になっていました。状況に応じて必要なものだけを提供したい、かつファイル分割のしすぎは抑えるようにしたいわけです。webpackが提供するハイブリッドなモジュールシステムwebpackは、これらの問題を解決するための機能が備わっています。モジュールの同期・非同期読み込みに対してのアプローチ、ファイルのバンドルに対してのアプローチをそれぞれ確認してみましょう。modulesのimportが使用できるようになりました。下記のように、非常にシンプルで扱いやすい記述をすることができます。element;}document.body.appendChild(component());同期的にだけでなく、RequireJSのような非同期的なモジュール読み込みの機能も備えています。次のように書くことでimportは実行時に指定されたモジュールを非同期に取得します。component');}また、async/await*を使用して下記のように書くことも可能です。element;}*注:async/awaitについてasync/awaitについては、次のシリーズなども参照してください。CodeGrid複数のモジュールを並列に読み込むことも可能です。Splitting)先ほどバンドルするツール側の課題について説明しました。理想はユーザーのアクセスするページで必要なコードのみがバンドルされ、読み込まれることでしょう。Splitting)」と呼ばれる機能によって、各ページで必要とされるコードとその依存関係にあるファイルだけをバンドルして提供する機能を備えています。コード分割によってバンドルされたファイルの固まりは「チャンク(chunk)」と呼ばれます。webpackが開発された経緯を踏まえると、webpackにとって重要な機能の1つであると言えるでしょう。各ページから依存される共通モジュールのコードが複数のチャンクで重複してしまうようなケースでは、その重複したコードを抜き出して新しいチャンクを作成するといった機能も備えています。コード分割の具体的な方法はここでは説明しきれないため、次回の記事で実際にwebpackの設定・実行を踏まえながら説明します。JavaScriptだけを対象にしないモジュールシステムwebpackでは提供するモジュールシステムが、JavaScriptしか対象にしない理由がないという考えのもと、下記の静的リソースもJavaScriptと同様にモジュールシステムを利用することが可能になっています。webpackを使用すると、これら静的リソースに対してもimportすることが可能になります。こちらも、次回以降に詳しく説明します。スタイルシート画像ウェブフォントテンプレート用のHTMLその他まとめ今回は主にwebpackが開発された経緯やその他のモジュールシステムとの違い、そしてwebpackが提供する理想的なモジュールシステムのアプローチについて説明しました。次回は実際にwebpackを導入し、基本的な使い方について解説します。智朗フロントエンド・エンジニアWeb制作会社、システム開発会社を経て、主にフレームワークを用いたサーバーサイドとフロントエンドをまたいだB2Bシステムの開発に従事。そのかたわら、JavaScriptへの興味が尽きず、静岡JavaScript勉強会の開催や、JavaScript関連の公式ドキュメントの翻訳などを行う。STUDIOを運用している。特定商取引法に基づく。