![見出し画像](https://assets.st-note.com/production/uploads/images/15666290/rectangle_large_type_2_8314470bf5fbee21f0105c3a1008300d.png?width=1200)
モジュールバンドラーはなぜモダンなフロントエンドの開発に必要なのか?
本格的にフロントエンドの開発をしていくにあたりモジュールバンドラーの役割を理解しておくことは非常に重要です。
近年どんどん複雑になっていくフロントエンドの開発フローにおいて「コードを書く」というのと同じくらい「開発環境の設定をする」ということが重要だからです。
そこでこのノートではモジュールバンドラーがなぜ必要なのかという観点から解説していきたいと思います。
基本的には私が普段使用しているWebpackを念頭に説明していきます。
モジュールバンドラーとは何をするものなのか?
モジュールバンドラーとは一言で説明すると複数のモジュールを依存関係を解決して一つにまとめるものになります。
モジュールというのはフロントエンドの開発においては「関数」や「コンポーネント」といった機能ごとに分けたファイルになります。
ではなぜ一つにまとめる必要があるのか?
それはブラウザ/サーバー間での通信プロトコルであるHTTP/1.1の仕組みに起因します。
HTTP/1.1では一度に処理できるリクエストの数が限られているためJSのリクエストをなるべく一つにまとめてリクエストの回数を減らすことが表示速度(パフォーマンス)の観点で優れているからです。
そうであれば最初から一つのファイルに全て書いておけばいいんじゃないかと思われるかもしれませんが、ある程度複雑なアプリケーションになると何千、何万行となってくるのでどこに何の処理を書いたのか探すだけでも一苦労です。
また複数人で開発するのが基本になるので同じファイルを更新していくわけにはいきません。同じ変数を使用していまい上書きしてしまうかもしれません(名前空間の汚染)。
そのためコードのメンテナンスのしやすさや読みやすさの観点からもモジュール単位で開発していく必要があります。
そこで基本的には一つの処理や機能(関数、コンポーネント)を一つのファイルに書いて他のファイルの中でそのモジュールが必要であればその都度読みこんで利用するというのが基本となります。
「開発する時は機能単位でなるべく細かくファイルごとに分けたい」という一方で「ブラウザにファイルを読み込む時はなるべく少ないファイルにまとめたい」という相反する理由があります。
モジュールバンドラーが複雑に見えるのはなぜか?
モジュールバンドラーは複数のファイルをまとめるものと説明しましたが実際にはそれ以外にも役割があり、これがモジュールバンドラーを複雑で理解しにくいものにしています。
ブラウザで表示するために必要なのはHTML、CSS、JSのファイルですが実際の開発では
- テンプレートエンジン (pug、Handlebarsなど)
- JSのフレームワーク(React,、Vue、Angularなど)
- Linterでの構文チェック
- CSSのプリプロセッサー(PostCSS、Sassなど)
- TypeScriptのトランスパイル
といったものを使って開発していきます。
ただブラウザはそのままでは理解できないのでHTML、CSS、JSのファイルに変換する必要があるのでそのためのツールが必要です。
さらに
- CSSにブラウザごとのprefixを付与する
- JSやCSSファイル、画像の圧縮
といった作業も必要になります。
Webpackの場合「loader」を使ってCSSや画像などのアセットを読み込んで「plugin」で様々な処理をすることができます。
これらの一部は以前であればGulp、Gruntなどのタスクランナーと呼ばれるツールを使っていたのですがWebpackでも代替可能になり、本来の「モジュールのバンドリング」以外のこともするようになったため、「モジュールバンドラー」の役割が複雑に見えるようになっていると言えます。
JavaScriptにおけるモジュールの歴史(Webpack以前)
モジュールバンドラー、特にWebpack以前のJavaScriptのモジュールはどうだったのかと思いますよね?
簡単におさらいしてみたいと思います。
もともとJavaScriptにはモジュールという概念はありませんでした。
なのでファイルを機能ごとに切り分けた時に発生する問題の一つが先ほども言及した「グローバルな名前空間の汚染」という問題です。
まだconstやletが登場する前はすべての変数をvarで定義する必要がありました。
ただしvarは上書きもできてしまいます。
なので別のファイルで同じ変数名を使っているとそのファイルによって上書きされて変数の中に意図しないものが代入されてしまうという問題が発生してしまいます。
そこで即時関数を使用することでグローバルな名前空間を汚染するのを防ぐという方法が取られます。
これはvarで定義した変数は関数内部でのみ参照できるという性質を利用したものです(関数スコープ)。
そしてタスクランナーと呼ばれるツールを使用してファイルを結合するというプロセスが取られていました(ビルドすると言ったりします)。
JavaScriptにおけるモジュールの歴史(Node.jsとWebpackの登場)
Node.jsの登場がJavaScriptにおけるモジュールを大きく進歩させます。
もともとJavaScriptはブラウザの上でしか動作しませんが、そのJavaScriptをサーバーなどのブラウザの外でも動くようにしようという動きが起こります。
その際の仕様としてCommonJSができました(始まりはServerJSプロジェクトという名前だったようです)。
このCommonJSという仕様ができたことでNode.jsが生まれます。
Node.jsはそのJavaScriptをブラウザ以外の環境でも動くようにするための実行環境を提供しました。
Node.jsが登場したことによってパッケージマネージャという概念ができます。
開発者がそれぞれ便利なツールを開発してnpmで公開できるようになり、他のプロジェクトでそのnpmを使用するというエコシステムができます。
タスクランナーとして言及したGulpやGruntなどもその一つです。
ES Modulesの登場
そしてついにJavaScriptにもES Modulesというモジュールの概念が取り入れられるようになりました。
しかしブラウザによっては対応していないものもあるため引き続きWebpack等のモジュールバンドラーを使用する必要はあります。
もともとJavaScriptが他のプログラミング言語と比較して足りない要素が多々あり、それを補う形で周辺ツールがたくさん出てきていて結果としてJavaScriptを取り巻く全体像が複雑になっているという背景があります。
今回は以上になります。
最後までお読みいただきありがとうございました。