- はじめに
- 第1章:バンドラーとは何か
- 第2章:歴史① ファイルがたくさんある問題
- 第3章:CommonJS と Node.js の登場
- 第4章:AMD vs CommonJS のブラウザ戦争
- 第5章:ついにバンドラー登場! Browserify
- 第6章:コラム IIFEパターン
- 第7章:ES Modules の登場と標準化
- 第8章:歴史② ブラウザがたくさんある問題
- 第9章:トランスパイルと Babel
- 第10章:webpack の登場と普及
- 第11章:webpack の問題点と次世代ツールの台頭
- 第12章:Vite の登場
- 第13章:webpack の後継争いと Bun
- 第14章:ツールの相関図を整理しよう
- 第15章:BabelとSWCの現実 まだBabelが必要な場面
- 第16章:結局どれを使えばいいのだ?
- 第17章:バンドラーを使わない標準の世界
- 第18章:20年の歴史を振り返って
- 学んだことまとめ
- まとめ
はじめに
ムーザルちゃんねる(むーさん・ざるさん)の動画「雰囲気で使ってる謎のツールJSバンドラーの世界」がとてもわかりやすく、バンドラーへの理解が深まったので備忘録として残しておきたいと思いました。動画の内容をそのまままとめるだけでは面白くないかと思い、ずんだもんと四国めたんの掛け合い形式に仕立て直してみました。
元動画の内容を個人の学習目的でアレンジしたものですので、内容に齟齬や誤りがある可能性があります。正確な情報はぜひ元動画でご確認ください。
第1章:バンドラーとは何か
ずんだもん:「ねえねえ、めたん!バンドラー(複数ファイルをまとめるツール)ってよく聞くのだけど、なんなのだ?ビートとかウェブパックとか名前は聞いたことあるのだけど、全然わからないのだ!」
四国めたん:「あら、名前くらいは知ってるのね。フロントエンド開発してたら絶対に出てくる言葉だもの。今日はバンドラーの世界を歴史を紐解きながらしっかり説明してあげるわ。」
ずんだもん:「やったのだ!でも歴史って言うと難しそうなのだ……なんか眠くなりそうなのだ……」
四国めたん:「失礼ね!でも大丈夫、ちゃんと面白いから。実はバンドラーって、ただのツールじゃなくて、開発者たちが長年抱えてきた『理想と現実の戦い』の産物なのよ。」
ずんだもん:「理想と現実の戦い……!なんかかっこいいのだ!聞きたいのだ!」
四国めたん:「まず最初に、バンドラーには『狭義』と『広義』の2つの意味があるの。狭義はシンプルで、複数のJavaScriptファイルをブラウザが読み込めるように1つのファイルにまとめること。バンドル=束ねる、だから『バンドラー』ってわけ。」
ずんだもん:「あ!だからバンドラーなのだ!バラバラのファイルをひとまとめにするのだね!なるほどなのだ!」
四国めたん:「そう、理解が早いじゃない。広義のバンドラーはもっと幅広くて、ウェブ開発全般に必要な作業を一手に引き受けるツールのことを指すわ。今は広義の意味で使われることが多いの。」
ずんだもん:「ウェブ開発全般って、具体的にどんなことをしてくれるのだ?」
四国めたん:「大きく分けると6つの役割があるわ。以下の通りよ」
- 📦 バンドル — ファイルの結合
- 🔄 トランスパイル — コードの変換処理
- 🗜️ ミニファイ — コードを圧縮・軽量化
- ✂️ ツリーシェイキング — 不要コードの削除
- 📂 コードスプリッティング — ファイルを分割配信
- ♻️ ホットリロード — 保存時に自動で再読込
ずんだもん:「い、一気にたくさん出てきたのだ!頭がいっぱいになりそうなのだ……!」
四国めたん:「一個ずつ説明するから大丈夫よ。でもまず全体像として、バンドラーは一言で言うと『JavaScriptのコードを最適化するツール』だって覚えておいて。」
ずんだもん:「最適化!それならなんとなくわかるのだ!より良くしてくれるってことなのだ!」
四国めたん:「そうよ。でもここで一つ疑問が湧くと思うんだけど、バンドラーを使わなくても開発できるんじゃないの?ってね。」
ずんだもん:「あ!そうなのだ!シンプルな方がいいのだ!」
四国めたん:「実は答えから言うと、今の時代はバンドラーを使わなくても開発はできるのよ。環境がかなり進化してるから。でも大規模な開発や、使うツールによっては必要不可欠な場面もある。なぜそうなったか、その歴史を追っていきましょう。」
第2章:歴史① ファイルがたくさんある問題
四国めたん:「バンドラーが登場した背景には、大きく2つの問題があったの。まず1つ目が『ファイルがたくさんある問題』よ。」
ずんだもん:「ファイルがたくさんあると何が困るのだ?」
四国めたん:「そもそもの話をすると、JavaScriptってわずか10日間で設計された言語なの。」
ずんだもん:「10日間!?なのだ!?そんなに短いのだ!ずんだ餅を10個食べ終わる前に言語ができちゃうのだ!?」
四国めたん:「……その例えはよくわからないけど(笑)。ブレンダン・アイクという人が、ネットスケープというブラウザ会社のためにIE(Internet Explorer/インターネット エクスプローラー:マイクロソフトが長年提供していたウェブブラウザ、現在は後継のEdgeに置き換えられた)との競争に勝つために急いで作ったの。」
ずんだもん:「ネットスケープ?なんなのだ?」
四国めたん:「かつてマイクロソフトのIEと激しいブラウザ戦争を繰り広げていた会社よ。それぞれ独自のブラウザを持っていて、IEに負けないために急いでJavaScriptを開発したの。」
ずんだもん:「ブラウザ戦争……!なんかドラマチックなのだ!」
四国めたん:「で、10日間で作ったから仕方ないんだけど、JavaScriptには当初モジュールシステム(ファイルを分割・再利用する仕組み)がなかったのよ。今のTypeScriptで import とか require とかやるじゃない?別のファイルから処理を読み込む仕組みのことよ。それがなかった。」
ずんだもん:「え!?じゃあ他のファイルのコードを使えなかったのだ!?それはつらいのだ!」
四国めたん:「当時は <script> タグでHTMLにJavaScriptファイルを読み込むしかなかったわ。アプリが大きくなると依存関係の管理が地獄になるし、ファイルが増えればHTTPリクエスト(サーバーへのデータ取得要求)も増えてパフォーマンスも悪化する。」
ずんだもん:「ファイルが100個あったら順番を全部覚えないといけないのだ!それは地獄なのだ!」
四国めたん:「さらに深刻な問題が『グローバル汚染(変数が全体から見えてしまう状態)』よ。<script> タグで読み込んだコードって、全部グローバルスコープ(変数が使える範囲)に存在してる。ブラウザで言うとwindowオブジェクトに全部所属してるの。別ファイルで宣言した変数が意図せず衝突したり、書き換えられたりするの。」
ずんだもん:「ひいいいなのだ!せっかく分けてるのに意味ないのだ!」
四国めたん:「だから『JavaScriptにもモジュールシステムが欲しい!』っていう要望が湧き上がってきたわけ。」
第3章:CommonJS と Node.js の登場
ずんだもん:「それでモジュールシステムができたのだ!?」
四国めたん:「2009年に『CommonJS(コモン ジェイエス:JSのモジュール仕様の一つ)』が登場したの。ただし、これはバンドラーじゃなくて『仕様』なのよ。」
ずんだもん:「仕様って、ツールじゃないのだ?」
四国めたん:「そうよ。仕様っていうのはいわばルールの約束書みたいなもの。実際に動くプログラムじゃなくて、『こういうふうにモジュールを扱いましょう』って決めたドキュメントよ。CommonJSにはモジュールシステムのほか、NPM(Node Package Manager/ノード パッケージ マネージャー:JSパッケージ管理システム)のような仕組みも含まれていたの。」
ずんだもん:「NPMってあのnpmなのだ!よく使うのだ!」
四国めたん:「そうよ。そしてこのCommonJSを最初から採用して実装したのが、同じく2009年に登場したNode.js(ノード ジェイエス:サーバーでJSを動かす環境)よ。」
ずんだもん:「Node.js!知ってるのだ!つまりNode.jsを使えばCommonJSが使えるってことなのだ!」
四国めたん:「正解。CommonJSの書き方は exports と require を使うの。今も require って書き方を見ることがあるでしょ?あれがCommonJSよ。ただし問題があって、これはNode.js限定で、ブラウザでは使えなかったの。」
ずんだもん:「せっかくいいものができたのに!なのだ!」
第4章:AMD vs CommonJS のブラウザ戦争
ずんだもん:「それでブラウザでもモジュールが使えるようになったのだ!?」
四国めたん:「そこで『ブラウザでもモジュールを使いたい!』って声が上がって、『AMD』というものが生まれたの。」
ずんだもん:「AMD!CPUみたいな名前なのだ!ライゼンとかのあのAMDなのだ!?」
四国めたん:「全然別物よ(笑)。Asynchronous Module Definition(エイシンクロナス モジュール デフィニション)の略で、非同期モジュール定義という意味ね。CPUのAMDとは何の関係もないわ。」
ずんだもん:「まぎらわしいのだ!(笑)」
四国めたん:「CommonJSは同期的(完了まで処理を止める方式)にモジュールを読み込む仕様だったの。ブラウザの場合はWebサーバーにファイルを取りに行かないといけないから、同期的だと処理が止まってしまう。だから非同期(待たずに次の処理を進める方式)で読み込むAMDが生まれたのよ。」
ずんだもん:「なるほどなのだ!でも今はAMDって聞かないのだ。結局どうなったのだ?」
四国めたん:「AMDはブラウザで使うために RequireJS(リクワイア ジェイエス:AMDの仕様を実装したブラウザ向けモジュールローダー) というライブラリで実装されたんだけど、依存関係がコールバックで書かれるからコールバック地獄(ネストが深くなり読みにくいコード)になる問題があった。」
ずんだもん:「コールバック地獄!あの波打つようなインデントのやつなのだ!見ただけで目が回るのだ!」
四国めたん:「そうそう(笑)。しかもNPMのほとんどのライブラリはCommonJS前提で作られてたから、AMDでは使いづらかったの。一応両方に対応しようとしたUMD(Universal Module Definition/ユニバーサル モジュール デフィニション:CommonJS・AMDどちらでも動くよう設計された統一モジュール仕様)というフォーマットもあったんだけど、対応してないライブラリもあって混乱が続いたの。」
ずんだもん:「エコシステムに馴染めなかったのだね……かわいそうなのだ」
四国めたん:「結果的にCommonJSが広く使われることになったわ。でも問題は残っていて、CommonJSはブラウザで動かないから、ブラウザでCommonJSを使うためのツールが必要になったの。」
ずんだもん:「それがついにバンドラーの登場なのだ!?」
第5章:ついにバンドラー登場! Browserify
四国めたん:「そうよ!ここでようやく狭義のバンドラーが登場するの。それが『Browserify(ブラウザリファイ:CommonJSをブラウザ向けに変換するツール)』よ。魔法使いのおじいちゃんがトレードマークのツールね。」
ずんだもん:「魔法使いのおじいちゃん!なんかかわいいのだ!」
四国めたん:「Browserifyは、CommonJSをブラウザで動くコードに変換するツールよ。exports/require はブラウザには搭載されてないから、それをブラウザで動く形に変換するの。」
ずんだもん:「変換した後のコードってどうなるのだ?」
四国めたん:「複数のファイルを1つの大きなファイル、例えば bundle.js にまとめてしまうの。その中に各ライブラリのコードがベタッとある。番号で管理されて、賢く呼び出せるようになってるわ。」
ずんだもん:「つまりバラバラのファイルを1個の巨大ファイルにまとめちゃうのだ!それがバンドルなのだ!」
四国めたん:「完璧な理解よ!大量のHTTPリクエスト問題が解決するし、スコープの問題もクリアになる。しかもNPMのライブラリも使えるようになった!」
ずんだもん:「一石三鳥なのだ!これでめでたしめでたしなのだ!」
四国めたん:「……残念ながら、まだ続きがあるのよ。」
ずんだもん:「え!なのだ!?」
第6章:コラム IIFEパターン
四国めたん:「ちょっと寄り道して、Browserifyみたいな仕組みを使わずにスコープ問題を解決しようとした昔ながらの手法を紹介するわ。IIFE(アイ・アイ・エフ・イー)パターンっていうの。」
ずんだもん:「アイフ?なんなのだ?」
四国めたん:「Immediately Invoked Function Expression(イミディエイトリー・インヴォークト・ファンクション・エクスプレッション)、即時実行関数式のことよ。(function() { ... })() みたいな、括弧がいっぱいついてる不思議なコードよ。」
ずんだもん:「あのなんか括弧がいっぱいついてる、見ると頭が痛くなるやつなのだ!」
四国めたん:「(笑)そうそう。関数をすぐ実行することで、その中の変数をローカルスコープに閉じ込めて、外に漏れないようにするの。エクスポートしたいものだけ return で外に出すっていう書き方ね。」
ずんだもん:「昔の人はそんな工夫をしてたのだ!えらいのだ!」
四国めたん:「今はほとんど使わない書き方だけど、古いコードを読む時に出てくることがあるから知っておくといいわ。」
第7章:ES Modules の登場と標準化
ずんだもん:「最終的にJavaScriptの公式モジュールシステムができたのだ!?」
四国めたん:「2015年のES2015(イーエス ニーゼロイチゴ:JavaScriptの2015年版仕様)で、ついにJavaScript公式の『ES Modules(イーエス モジュールズ:JS公式のモジュール仕様)』が標準として定義されたの!これが今の import/export よ。」
ずんだもん:「やったのだ!これが import/export のやつなのだ!」
四国めたん:「CommonJSとの大きな違いは静的解析(実行前にコードを解析できること)ができること。CommonJSは動的にモジュールを制御できるの。実行してみないと何がエクスポートされるか決まらないのよ。」
ずんだもん:「えっとどういうことなのだ?」
四国めたん:「例えばこういうコード。if (Math.random() > 0.5) { module.exports = functionA; } else { module.exports = functionB; } みたいな感じで、実行するたびに違う関数がエクスポートされる、なんてことができちゃうの。」
ずんだもん:「え!実行するまでどっちかわからないのだ!?それはわかりづらいのだ!」
四国めたん:「でしょ。一方のES Modulesは静的解析できるから、実行しなくてもどのコードが必要かが事前にわかる。だから……」
ずんだもん:「ツリーシェイキング(不要コードを事前に除去する最適化)がやりやすくなるのだ!」
四国めたん:「完璧よ!ツリーシェイキングは使われていないコードを削除する最適化だから、静的解析できるESM(ES Modules:詳細は前述)と相性が抜群なの。」
ずんだもん:「ツリーシェイキング……木を揺らして不要な葉っぱを落とすイメージなのだ!」
四国めたん:「……まあ、そういうイメージでいいんじゃないかしら。ちなみに何かの木の実を取る時に木を蹴ったりするじゃない?」
ずんだもん:「あ!くりの木とかなのだ!揺らして落とすやつなのだ!」
四国めたん:「そういうイメージで覚えておけばいいわ(笑)。落ちたもの=使っているコード、落ちないもの=使っていないコードで削除、って感じね。」
ずんだもん:「でもちょっと待つのだ。さっきCommonJSが天下を取ったのに、また別のモジュールシステムが出てきたのだ!またキングダム(※)が始まるのだ!?」
(※)キングダム:天下統一をめぐる争いを描いた人気漫画、戦略や人心掌握の描写が深くビジネス書としても読まれている、ここでは『また覇権争いが始まる』という意味)
四国めたん:「ふふ、鋭いわね。CommonJSは野良ルール、ES Modulesが公式ルールって感じで並立する時代になったのよ。でも今は明確にESMが標準よ。」
ずんだもん:「野良ルールなのにものすごく広まったのだ……CommonJSすごいのだ!」
四国めたん:「そうよ。でもESMがブラウザで広く使えるようになったのは2019〜2020年ごろ。2015年に標準化されてから5年近くかかったの。その間はバンドラーが現実的に必要だったわ。」
ずんだもん:「5年!なのだ!その間はバンドラーが必要だったのだ!」
第8章:歴史② ブラウザがたくさんある問題
四国めたん:「次の問題は『ブラウザがたくさんある問題』よ。クロスブラウザ対応(複数ブラウザで同じ動きを実現すること)問題とも言うわ。」
ずんだもん:「クロスブラウザ!よく聞くのだ!大変なやつなのだ!」
四国めたん:「2000年代初頭はJavaScriptエンジンのブラウザ間の差がものすごく大きかったの。特にIEが憎い、なんて話がエンジニアの間では伝説になってるわ。」
ずんだもん:「IEが憎い!笑えないけど笑えるのだ(笑)」
四国めたん:「例えばクリックイベントを書こうとすると、普通は addEventListener を使うんだけど、IE8以下はこれに対応してなくて、attachEvent という別のAPIを呼ばなきゃいけなかったの。」
ずんだもん:「えっ!同じことをするのにブラウザによって書き方が違うのだ!?」
四国めたん:「しかもそういう本質的じゃないコードがJavaScriptにもCSSにも山ほど存在してたの。昔はIE専用のCSSプロパティに先頭にアンダースコアをつけると読み込まれる、なんてコテ先のテクニックまであったのよ。」
ずんだもん:「アンダースコア!?なんか呪文みたいなのだ!」
四国めたん:「今は何の役にも立たない知識ね(苦笑)。当時のエンジニアたちは本来やりたい機能じゃなく、ブラウザ差異の吸収という修行に多大な時間を使ってたわ。」
ずんだもん:「役に立たない修行……つらいのだ……でも今のエンジニアはその修行のおかげで楽できてるのだ!先人たちに感謝なのだ!」
四国めたん:「その苦労を救ったのが『jQuery(ジェイクエリー:クロスブラウザ対応ライブラリ)』よ。1つの書き方でメジャーなブラウザ全てで同じ動きを実現できたの。」
ずんだもん:「一気に解決なのだ!これでめでたしめでたしなのだ!」
四国めたん:「……また続きがあるのよ。」
ずんだもん:「またなのだ!」
四国めたん:「jQueryはあくまでJavaScriptの上で動くライブラリ。ブラウザ自体が新しい構文を理解できなかったら手も足も出ないの。例えばアロー関数(=>)をIEで使おうとすると、ブラウザがその記号を見た瞬間に構文エラーでクラッシュするのよ。jQueryには手も足も出ない問題ね。」
ずんだもん:「そっか!jQueryは普通のJavaScriptの上で動くから、ブラウザが新しい構文を理解できなかったら門前払いなのだ!」
四国めたん:「そこで生まれた新しい概念が『トランスパイル(新しい構文を古い構文に変換)』よ。『動かないなら変換してしまえ』という発想ね。」
第9章:トランスパイルと Babel
ずんだもん:「トランスパイル!コンパイルみたいな名前なのだ!」
四国めたん:「鋭い!コンパイルに近い概念ね。最新の構文で書いたコードを、古いブラウザでも動くコードに変換するのよ。例えばアロー関数を無名関数式に変換するような感じ。const add = (a, b) => a + b を var add = function(a, b) { return a + b; } に変換するような感じね。」
ずんだもん:「開発者は新しい書き方で書けて、古いブラウザにも動くコードが届く。最高なのだ!」
四国めたん:「このトランスパイルを実現するために『AltJS(オルトジェイエス:JSに変換される別言語)』と『Babel(バベル:JSを古い形式に変換するツール)』の2つのアプローチが生まれたわ。」
ずんだもん:「AltJSって何なのだ?」
四国めたん:「JavaScriptの代替言語のことよ。CoffeeScriptとかTypeScriptとか。別の言語で書いて、トランスパイルでJavaScriptに変換する前提の言語ね。」
ずんだもん:「TypeScript!大好きなのだ!あれもAltJSだったのだ!」
四国めたん:「CoffeeScriptは2009年に、TypeScriptは2012年に生まれたわ。CoffeeScriptはRuby(ルビー:まつもとゆきひろ氏が開発したプログラミング言語)っぽい書き方ができて当時かなり人気があったの。Rails(レイルズ:RubyでWebアプリを素早く構築できるフレームワーク)でもCoffeeScriptが正式採用されてた時期があったのよ。」
ずんだもん:「コーヒースクリプト……コーヒーが好きな人が作ったのだ!?」
四国めたん:「(笑)さあ、どうかしらね。TypeScriptはJavaScriptのスーパーセット(既存の言語を完全に内包しつつ機能を拡張したもの)として設計されてて、型情報を乗せた形よ。Delphi(デルファイ:1995年登場のWindows向け開発ツール)やC#(シーシャープ:Microsoftが開発したオブジェクト指向言語)を作った人が作ったの。」
ずんだもん:「だから既存のJavaScriptコードがそのままTypeScriptとして動くのだ!なるほどなのだ!」
四国めたん:「一方のBabelは、JavaScriptのまま書いて、古いブラウザ向けに変換するツールよ。元々の名前が 6to5 って言って、ES6をES5に変換するというそのままの名前だったの。」
ずんだもん:「わかりやすい名前なのだ(笑)そのBabelを作ったのが高校生だって言ってたのだ!高校生!」
四国めたん:「セバスチャン・マッケンジーというすごい人よ。その後もRome(ローマ:JS開発に必要なツールをオールインワンで提供しようとした統合ツールチェーン)というさらに野心的なプロジェクトに挑戦したりと、業界に多大な影響を与えてる人ね。」
ずんだもん:「高校生がそんなすごいものを……ずんだもんは高校生の時何してたのだ……ずんだ餅食べてたのだ……」
四国めたん:「(笑)まあ、私たちは彼らの作ったものをありがたく使わせてもらえばいいのよ。」
ずんだもん:「そうなのだ!感謝して使うのだ!……でも待つのだ。高校生が作ったものに乗っかってお金を稼いでるずんだもんは、いったい何をしてるのだ……?」
四国めたん:「……それはね、その高校生が作ったものの使い方を一生懸命調べて、プロジェクトに適用してるのよ。それも立派な仕事よ!(少し動揺しながら)」
ずんだもん:「め、めたんも同じなのだ!(笑)」
四国めたん:「うるさいっ!続けるわよ!補足しておくと、彼が作ったのはBabelの基盤となるコンパイラ(ソースコードを別形式に変換するプログラム)の仕組みで、JSXの変換はその上に乗ったプラグインが担当してるのよ。」
ずんだもん:「あ!じゃあ『Babelを作った=JSXも全部作った』ではないのだね!」
四国めたん:「そうなの。BabelはAST(Abstract Syntax Tree/アブストラクト シンタックス ツリー:コードを木構造に分解した中間表現)に基づく変換基盤を提供して、JSX変換はBabelプラグインが行う、という分担ね。整理すると、Browserifyは複数ファイルを結合して依存関係を解決した。Babelは新しい構文を古いブラウザでも動くように変換した。この2つが別々のツールとして存在してたの。」
ずんだもん:「あれ?じゃあ両方使わないといけなかったのだ?それは大変なのだ!」
四国めたん:「そうなの。そこに登場したのが、これらを統合しようとした次のツールよ。」
第10章:webpack の登場と普及
ずんだもん:「ついに来たのだ!webpack!名前はよく聞くのだ!」
四国めたん:「そう、webpackよ!狭義のバンドラーが広義のバンドラーに進化した瞬間ね。Browserifyの作者はUnix哲学(※)に忠実で『1つのプログラムは1つのことをうまくやれ』という姿勢だった。だからBrowserifyはバンドル(結合)だけに徹してたの。」
(※)Unix哲学(ユニックス テツガク):『1つのツールは1つのことだけをうまくやれ』という設計思想
ずんだもん:「こっちはバンドル専門、あっちは変換専門って分けてたのだ!」
四国めたん:「webpackは違ったの。『ローダー(外部ツールと連携する仕組み)』という機能を使って、Babelのような変換ツールとの連携も含め、とにかく何でも1つで完結させようとしたのよ。BabelだけじゃなくSWC(スウィフト ウェブ コンパイラー:Rustで書かれた高速なJSトランスパイラー)やTerser(ターサー:不要なコードや空白を除去してJSを軽量化するツール)など複数の変換ツールをオプションで組み合わせられる柔軟さがあったわ。」
ずんだもん:「バンドルも変換もwebpack1つでできるのだ!それは便利なのだ!」
四国めたん:「しかもwebpackはCSS、画像、Sassまでもモジュールとして扱えるようにしたの。コンポーネント思考が流行ってきた時代に、CSSも画像もJSの中からimportできるって、これは革命的だったわ。」
ずんだもん:「確かに今のReactでCSSとか画像をimportするのだ!あれwebpackのおかげなのだ!」
四国めたん:「そしてwebpackが解決したもう一つの大きな問題が『コードスプリッティング(ページ別にJSを分割配信する手法)』よ。Browserifyって全部のファイルを1つにまとめちゃうんだけど、今見てるページに関係ないコードまで含まれちゃうの。アプリが大きくなればなるほど無駄なコードが増えて遅くなるのよ。」
ずんだもん:「コードスプリッティングとツリーシェイキングって似てるのだ?違うのだ?」
四国めたん:「いい質問ね。ツリーシェイキングは『大きなライブラリの使ってない機能を削除する』こと。コードスプリッティングは『全部使うんだけど、このページでは一部しか使わないから分けて配信する』こと。どちらも無駄を減らすけどアプローチが違うわ。」
ずんだもん:「ツリーシェイキングは要らない枝を切り落とす、コードスプリッティングは使う時だけ取り出す、みたいな感じなのだ!」
四国めたん:「素敵なたとえね。そしてwebpackの普及に決定的な追い風となったのがReactとJSXよ。JSXはJavaScriptじゃないから変換が必要。だからReactを使うにはバンドラーや変換ツールが必須になったの。」
ずんだもん:「React + webpack + Babel という黄金コンビが生まれたのだ!」
四国めたん:「そうよ。ReactのドキュメントでもwebpackでBabelを使う構成が紹介されてたから、フロントエンド開発全体でこの組み合わせが当たり前になったわ。Vue(ヴュー:軽量さと学習しやすさが特徴のUIフレームワーク)、Angular(アンギュラー:Google製のフルスタックフロントエンドフレームワーク)、Svelte(スヴェルト:ビルド時にコンパイルして軽量なJSを生成するフレームワーク)……後続のフレームワークにも広がって、ツールを使うことが前提の開発スタイルになったのよ。」
第11章:webpack の問題点と次世代ツールの台頭
ずんだもん:「でも2020年代に転換期を迎えたって言ってたのだ!webpackに問題があったのだ?」
四国めたん:「webpackには3つの大きな問題があったの。①設定ファイルが複雑になること、②動作が遅いこと、③最適化の余地がまだあること。」
ずんだもん:「設定ファイルが複雑になるのは、めたんも苦手だったのだ?」
四国めたん:「……認めるわ。正直難しくて、なるべく設定ファイルに触りたくなくて逃げ回ってたくらい(少し照れながら)。」
ずんだもん:「めたんが逃げ回るなんて珍しいのだ!(笑)」
四国めたん:「うるさいっ!でもそれくらい複雑だったってこと。しかもビルドに数分、大規模なプロジェクトだと数十分かかるなんてことも普通にあったの。」
ずんだもん:「数十分!?その間ずんだ餅でも食べてたのだ!?」
四国めたん:「それで次世代ツールが登場してくるの。3つの問題それぞれへの答えがあるのよ。」
ずんだもん:「3つの問題に3つの答えなのだ!教えてほしいのだ!」
四国めたん:「まず問題①の『最適化』に対する答えが『Rollup(ロールアップ:ESMベースの軽量バンドラー)』よ。webpackが登場した2010年代はCommonJSが主流だったから、webpackのデフォルトがCommonJS対応だったの。でもCommonJSは静的解析が難しいからツリーシェイキングがうまくできない。RollupはES Modulesをデフォルトにしてたから最適化されたバンドルができたのよ。」
ずんだもん:「だからRollupは特にライブラリ開発で人気があったのだ!」
四国めたん:「そうよ。webpackより複雑なことはできない分、設定はシンプルで使いやすかったわ。」
ずんだもん:「なんか……1回使ったけどその後あんまり使わなくなった感じがするのだ……」
四国めたん:「ふふ、まあそういう人も多いわね。1回ちゃんと向き合ったけど、その後疎遠になったというか……(遠い目)。でもライブラリ開発では今も現役よ。」
ずんだもん:「問題②の設定が複雑問題への答えは何なのだ!」
四国めたん:「それが『Parcel(パーセル:設定不要のバンドラー)』。ゼロコンフィグ(設定ファイル不要で動く)を掲げた、何も設定しなくても動くツールね。」
ずんだもん:「ゼロコンフィグ!なんと太っ腹なのだ!webpackの設定で逃げ回ってためたんにも使えるのだ!」
四国めたん:「……余計なお世話よ!でも今もけっこう人気があるツールよ。」
ずんだもん:「問題③の動作が遅い問題の答えは何なのだ!」
四国めたん:「それが『esbuild(イーエス ビルド:Go製の超高速バンドラー)』よ!ここで大きなブレイクスルーが起きたの。今まで『JavaScriptのツールはJavaScriptで書く』が当たり前だったの。でもesbuildはGo言語で書かれてて、webpackと比べて数十倍〜数百倍の速度でビルドできるの!」
ずんだもん:「数十倍!?数百倍!?なのだ!桁が違うのだ!」
四国めたん:「これがきっかけで、高速言語でビルドツールを書き直す流れが始まったの。主にRust(ラスト:メモリ安全性と実行速度を両立したシステムプログラミング言語)が使われることが多くて、BabelをRustで書き直した『SWC(Speedy Web Compiler/スピーディー ウェブ コンパイラー:Rust製の高速JSコンパイラ)』だったり、RollupをRustで書き直した『Rolldown(ロールダウン:Rust製の高速バンドラー)』だったり。」
ずんだもん:「SWC!Speedy Web Compilerなのだ!略称の意味がやっとわかったのだ!」
四国めたん:「ちなみに疑問よね。JavaScriptのツールはJavaScriptじゃなくていいの?ってね。」
ずんだもん:「あれ、でも考えてみたらそうなのだ!手元で動けばいいんだから、言語は関係ないのだ!むしろGoやRustの方が速いなら絶対そっちがいいのだ!」
四国めたん:「正しい理解よ。ビルドツールはブラウザで動くわけじゃなくて、開発者の手元のマシンで動くものだから、何の言語で書いてあっても関係ないの。速ければ速いほどいい。」
第12章:Vite の登場
ずんだもん:「そしていよいよViteなのだ!ビート!!」
四国めたん:「Viteよ(フランス語で『速い』という意味)!現在のフロントエンド開発の主役と言っていいわね。内部でesbuildとRollupを賢く使い分けてるの。開発環境(ローカルでの作業環境)ではesbuildの高速さを活かして、本番環境(実際にユーザーが使う環境)ではRollupでより最適化されたバンドルを生成するの。」
ずんだもん:「開発時と本番時で違うツールを使い分けるのだ!賢いのだ!」
四国めたん:「ViteはVueを開発したエヴァン・ユーさんが中心となって作ったツールで、VoidZeroという会社が主導してるの。次のVite v8からは内部がRollupからRolldownに全面移行する予定で、さらに高速化される見込みよ。」
ずんだもん:「進化し続けてるのだ!ユーザー満足度も高いのだ!」
四国めたん:「そうよ。利用率のアンケートでも、webpackは利用率は高いけど満足度が低い。Viteは利用率も伸びてて満足度も高い、という結果が出てるわ。」
ずんだもん:「それはViteを使うしかないのだ!」
第13章:webpack の後継争いと Bun
ずんだもん:「あとTurbopackとかRspackっていうのも出てきたのだ!」
四国めたん:「そうよ。webpackの後継・互換ツールも生まれてるの。Turbopack(ターボパック:webpack後継の高速バンドラー)はwebpackを作った開発者がVercel(ヴァーセル:Next.jsを作る会社)に移ってから開発したツールよ。Next.js 15からは開発環境でTurbopackがデフォルトになったわ。」
ずんだもん:「じゃあNext.jsユーザーは知らぬ間にTurbopackを使ってるのだ!」
四国めたん:「Turbopackは変換をSWCに任せているわ。そして結合(バンドル)の部分はTurbopack自身が担当してるの。変換と結合で担当ツールが分かれてるのが特徴ね。」
ずんだもん:「なるほどなのだ!じゃあSWCがいてTurbopackがいるから2つのツールが連携してるのだ!」
四国めたん:「そうよ。ちなみに今はNext.js 15が開発環境でTurbopackがデフォルト。Next.js 16からは本番環境でもTurbopackが使われる予定よ。そしてTurbopackはまだNext.jsの内部専用で、単体では公開されてないの。」
ずんだもん:「Rspack(アールエスパック)はTikTokが開発したやつなのだ!なんかすごい組み合わせなのだ!」
四国めたん:「RspackはwebpackとAPIの互換性があるのが特徴で、webpackからの移行がしやすいの。webpackのプラグインエコシステムをある程度そのまま使えるから、移行コストが低いのよ。」
ずんだもん:「既存のプロジェクトをwebpackから乗り換えやすいのだ!便利なのだ!」
四国めたん:「Bun(バン:JS実行環境兼バンドラー)はまた違っていて、JavaScriptランタイム自体がバンドル機能を内蔵してる。テスト機能まで内蔵してて野心的なの。」
ずんだもん:「めたんはBunのことが好きそうなのだ!」
四国めたん:「……まあ、可能性は感じてるわ。将来有望なツールよ。」
ずんだもん:「やっぱり好きなのだ!(笑)」
四国めたん:「うるさいっ!続けるわよ!」
第14章:ツールの相関図を整理しよう
ずんだもん:「なんかここまでいっぱいツールが出てきて頭がぐるぐるするのだ!整理してほしいのだ!」
四国めたん:「じゃあ大きく3つのカテゴリに分けてみましょう。①変換系(トランスパイル)、②結合系(バンドル)、③統合ツール(ビルドツール)よ。」
ずんだもん:「変換系はどんなものなのだ?」
四国めたん:「変換系の代表が『Babel』と『SWC』ね。BabelはJavaScript/JSXを古いブラウザ向けに変換する。SWCはBabelをRustで書き直した高速版。TypeScriptのコンパイルなら tsc もあるわ。」
ずんだもん:「結合系はなんなのだ?」
四国めたん:「結合系の代表が『Rollup』と『Rolldown』ね。RolldownはRollupをRustで書いた高速版。esbuildは変換と結合両方できる高速ツールよ。」
ずんだもん:「統合ツールはなんなのだ?」
四国めたん:「統合ツールは『webpack』『Vite』『Parcel』『Turbopack』『Rspack』ね。これらは変換も結合も含めた開発に必要な一連の処理をまとめてやってくれるの。」
ずんだもん:「なんかツールが別のツールを内部で使ってたりするのが面白いのだ!ViteはesbuildとRollupがいるのだ!」
四国めたん:「そうなのよ。バンドラー界隈の分かりにくさって、同じ横並びにいると思ってたツールが実は依存関係にあったりするから。この構造を理解しないと全体像が掴みにくいのよね。」
ずんだもん:「Vite v8からはesbuildじゃなくてRolldownになるのだ。OXC(Rust製の高速パーサー)っていうRust製のパーサーをRolldownが使ってるのだ!どんどん置き換えられてるのだ!」
四国めたん:「そうよ。派閥分けすると、ViteやRolldownを中心とするVoidZero系と、Vercel/Next.js系などに分かれてきてるわ。」
第15章:BabelとSWCの現実 まだBabelが必要な場面
ずんだもん:「そういえばめたん、SWCがBabelの高速版って言ってたのだ。じゃあもうBabelは完全にいらなくなったのだ!?」
四国めたん:「そうじゃないのよ。ここが大事なポイントね。SWCへの移行は確かに進んでいて、Next.jsでも採用されてるわ。でも完全にBabelを捨てられているわけではないの。」
ずんだもん:「え!?なのだ!?どういうことなのだ!?」
四国めたん:「Reactコンパイラー(ReactのコードをReactが自動最適化するための公式ツール)など、一部の機能はまだBabelでないと動かないのよ。Reactコンパイラーはまだ開発中のツールで、SWCプラグインとしての対応が追いついていないから、現時点ではBabelを使う必要があるの。」
ずんだもん:「なるほどなのだ!だからwebpackの相関図でSWCとBabelが両方書いてあったのだ!どちらかしか使えないわけじゃなくて、場合によって使い分けるのだ!」
四国めたん:「そうなの。現場の実態としては、SWCが使えるところはSWCを使って高速化しつつ、Reactコンパイラーなどまだ対応が追いついていない機能だけBabelに頼る、という混在状態になってるケースもあるわ。」
ずんだもん:「完全に移行したいけど、できないところもある……それがリアルなのだ!」
四国めたん:「そうよ。ツールの世界は『最新が正義』ではなくて、使いたい機能が対応してるかどうかで選ぶことが大事。SWCは高速で素晴らしいツールだけど、エコシステムの対応がBabelより遅れている部分は今もあるの。」
ずんだもん:「そういえばReactコンパイラーって最近よく聞くのだ!どんなものなのだ!?」
四国めたん:「Reactコンパイラーは、Reactのコードを自動的に最適化してくれるツールよ。今まで手動で useMemo や useCallback を書いて再レンダリングを防いでいたところを、コンパイラーが自動でやってくれる。つまり書くコードがシンプルになって、パフォーマンスも上がるというすごいツールなの。」
ずんだもん:「それはすごいのだ!useMemoって書くのめんどくさかったのだ!!」
四国めたん:「でしょ。だからReactコンパイラーへの期待は大きいのよ。ただ現時点ではまだBabelに依存している部分があって、SWCだけで完全に動かすにはもう少し時間がかかりそうね。」
ずんだもん:「なるほどなのだ!SWCが全部置き換えるのはもう少し先なのだ!」
四国めたん:「そういうこと。ツールの進化はリリースを追いながら見ていくことが大事よ。」
第16章:結局どれを使えばいいのだ?
ずんだもん:「ここが一番知りたかったのだ!どれを使えばいいのだ!?」
四国めたん:「失敗したくないなら『Vite』を使いなさい、が今の答えよ。」
ずんだもん:「はっきり言ってくれてありがとうなのだ!理由はなんなのだ?」
四国めたん:「理由は3つ。①今一番使われていて情報量が多い。②実際に使ってみるとトラブルが少ない、すぐ動く。③Vite v8で動作速度がさらに高速化されるので弱点がなくなる。」
ずんだもん:「なるほどなのだ!でもNext.jsをよく使う人はどうなのだ?」
四国めたん:「Next.jsを使う限りはViteを直接使う機会はないわ。内部にTurbopackやSWCが入ってるから意識しなくていいの。」
ずんだもん:「じゃあNext.jsユーザーはバンドラーを気にしなくていいのだ!」
四国めたん:「でもViteを使うシーンがあるとすれば、素のReactを使う時や、SvelteKit(スヴェルトキット:Viteを標準採用するSvelteの公式フルスタックフレームワーク)など他のフレームワークを使う時ね。」
ずんだもん:「あと小さなツールレベルなら何がいいのだ?」
四国めたん:「TypeScriptをJavaScriptに変換するだけなら tsc で十分だし、設定なしにすぐ始めたいならParcelもいいわ。Bunを使ってるならBun自体のビルド機能でも一通りできるわよ。」
ずんだもん:「迷ったらVite!それ以外は用途で選ぶのだ!」
第17章:バンドラーを使わない標準の世界
ずんだもん:「最後に一番気になってたやつなのだ!バンドラーを使わない開発って本当にできるのだ!?」
四国めたん:「できるのよ。素朴にJavaScriptを使うだけならバンドラーは不要よ。」
ずんだもん:「やったのだ!標準大好きなのだ!」
四国めたん:「理由をまとめると、まずES Modulesがブラウザで標準サポートされてること。<script type="module"> を使えばimportが使えるの。次に、HTTP/2やHTTP/3(高速な新しい通信プロトコル)が普及してきたから、ファイルが多くてもHTTPリクエストのオーバーヘッドが昔ほどひどくない。1つのコネクションで複数のリクエストを並行処理できるのよ。」
ずんだもん:「なるほどなのだ!昔は1ファイル1リクエストで遅かったけど、今はまとめて送れるのだ!」
四国めたん:「さらに補足しておくと、Node.jsでTypeScriptをそのまま実行できるようになったのはv22.6以降よ(--experimental-strip-types フラグが必要)。Node.js 24からはデフォルトで有効化されたわ。」
ずんだもん:「v22.6からなのだ!トランスパイルも不要になってきてるのだ!すごい時代なのだ!」
四国めたん:「あとは『Import Maps(インポート マップス)』という機能があって、ES Modulesのパスのエイリアスを設定できるの。バンドラーなしでも import { useState } from 'react' みたいな書き方に近い感覚で使えるようになるのよ。」
ずんだもん:「CDN(Content Delivery Network/コンテンツ デリバリー ネットワーク:ライブラリやアセットをインターネット上のサーバーから直接配信する仕組み)のURLを毎回書かなくていいのだ!便利なのだ!」
四国めたん:「さらに『ESM.sh(イーエスエム ドット エスエイチ:CDN経由でライブラリを配信するサービス)』というCDNを使うと、ライブラリのツリーシェイキングまでやってくれるの。必要な機能だけを含んだファイルを配信してくれるから最適化もできるわ。」
ずんだもん:「バンドラーなしでもかなりのことができるのだ!」
四国めたん:「ただし大規模なサービスでは、バンドラーを使った最適化は今のところ必要不可欠よ。規模によって使い分けるのが現実的な答えね。」
ずんだもん:「なるほどなのだ……ちょっとがっかりもするけど、状況によって判断するのだね!」
第18章:20年の歴史を振り返って
ずんだもん:「めたん、今日は本当にありがとうなのだ!バンドラーのモヤモヤが晴れたのだ!最後に全体をまとめてほしいのだ!」
四国めたん:「この20年のフロントエンド史を一言で言うと『理想とブラウザの戦い』だったと思うわ。」
ずんだもん:「理想とブラウザの戦い……!かっこいいのだ!」
四国めたん:「モジュールのない世界にCommonJSとBrowserifyが戦った。クロスブラウザ問題にjQueryが戦った。型のない世界にTypeScriptが現れた。新しい構文が動かない問題にBabelとwebpackが戦った。そしてJSXという独自記法が生まれてはバンドラーが変換した。」
ずんだもん:「それぞれの時代に、その時代の問題を解決するために新しいツールが生まれてきたのだ!」
四国めたん:「そうよ。バンドラーって最終的には『理想と現実の架け橋』なんだと思う。開発者が書きたいコードと、ブラウザが実行できるコードの間にあるギャップを埋めるのが、バンドラーの本質的な役割なのよ。」
ずんだもん:「なんか感動したのだ……!バンドラーって意地悪な存在じゃなくて、ちゃんと意味があったのだ!感謝して使えるのだ!」
四国めたん:「そうよ。『雰囲気で使ってた』のが『ちゃんと理由があってこうなってる』に変わったでしょ?」
ずんだもん:「変わったのだ!もうバンドラーを見ても怖くないのだ!ありがとうなのだ〜!!」
四国めたん:「……どういたしまして。まあ、ちゃんと理解できたなら教えた甲斐があったわ(少し嬉しそうに)。」
ずんだもん:「あ、めたんが照れてるのだ!かわいいのだ!」
四国めたん:「うるさいっ!次はNode.jsのバージョン管理とかについて話しましょうか。それよりも早く復習しなさい!」
ずんだもん:「わかったのだ!まずはViteを使ってみるのだ!いざ実践なのだ!!」
学んだことまとめ
| 項目 | 内容 |
|---|---|
| バンドラー(狭義) | 複数JSファイルを1つにまとめるツール |
| バンドラー(広義) | バンドル・トランスパイル・ミニファイ等を一手に担うツール |
| 歴史の流れ | モジュールなし → CommonJS → AMD → Browserify → ES Modules → webpack → Vite |
| 変換系の変遷 | Babel → SWC(Rust製高速版) |
| 結合系の変遷 | Rollup → Rolldown(Rust製高速版) |
| 統合系の現状 | webpack → Vite(主流)・Turbopack(Next.js内部)・Rspack(webpack互換) |
| BabelとSWCの現実 | SWCへの移行が進むが、Reactコンパイラーなど一部機能はまだBabelが必要 |
| 迷ったら | Vite:情報量・安定性・速度の三拍子が揃っている |
| バンドラーなしも可能 | ESM + Import Maps + ESM.sh で小規模開発は対応できる |
| バンドラーの本質 | 理想と現実の架け橋 |
まとめ
バンドラーの歴史と役割を、ずんだもんと四国めたんの掛け合い形式で振り返りました。「なぜ存在するのか」という背景を知ることで、ツール選定への理解が深まれば幸いです。
あらためて、わかりやすい解説動画を制作してくださったムーザルちゃんねるのむーさん・ざるさんに感謝申し上げます。