2024年10月15日
執筆
有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)に所属するテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。著書に『Bootstrap 5 フロントエンド開発の教科書』、『作って学べるHTML+JavaScriptの基本』など。
監修
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。
主な著書に「独習」シリーズ、「これからはじめるReact実践入門」、「改訂3版 JavaScript本格入門」他、著書多数。
「新発見!フロントエンド技術の今」の連載。第12回のテーマはフロントエンドアプリの配布に欠かせないバンドラーです。
バンドラーとは、JavaScriptファイルやCSSファイル、画像ファイルなどの、静的アセットをまとめてバンドル化するツールです。主に、JavaScriptモジュールのバンドルに主眼が置かれていることから、モジュールバンドラーとも呼ばれます。また、単純にビルドツールと呼ばれることもありますが、表しているものはほとんど同じです。
フロントエンドに限らず、プロジェクトの規模が大きくなってくると、欠かせないのがモジュール化です。モジュール化とは、機能をファイル単位で分割してコードの見通しを向上し、再利用もしやすくすることです。ただ、モジュール化により読み込み時間が増大したり、依存関係を把握しにくくなったりするなどといった問題も出てくるため、単一あるいは必要に応じて複数のファイルにまとめることで、取り扱いやすさと性能を向上させるのがバンドルです。
モジュールの作成や読み込みの方法を定めたモジュールシステムには、CommonJS Modulesと、ES Modules(ESM)があり、第8回で簡単に紹介しました。現時点で使われているほとんどのバンドラーは、この双方に対応しています。
バンドルの成果物のファイル名にダイジェスト(ファイル内容などから算出される識別名)を付与する機能もあります。ダイジェストにより、更新の都度、ファイル名が変わるので、ブラウザキャッシュによる性能向上の恩恵を受けながら、ファイルの更新に即座に対応できるようになります。
バンドラーはファイルをまとめるだけではなく、トランスパイルや最適化などの機能も提供します。トランスパイルとは、Translation+Compileの造語で、TypeScriptのようなAltJS、JSXのようなメタ言語をブラウザが解釈できるJavaScriptなどの言語に変換することです。最近では少なくなりましたが、ES6を解釈できないブラウザ向けにES6以降のコードを変換する作業も指します。トランスパイラには、Babelがよく使われており、バンドラーが内蔵する場合もあります。
バンドラーは、空白、改行、コメントの除去、識別子の短縮などによる最小化/圧縮処理、そしてTree Shakingといった最適化処理も提供します。バンドルのサイズが小さくなるので、読み込みと実行時間の短縮に貢献します。
Tree Shakingは、使用されない関数、変数、モジュールなどを除去します。ES Modulesのimport/exportの記述に基づきコードを静的に解析、コードの依存関係をツリー構造(Tree)に転換、使用されないコードを特定して除去する(Shaking)といった処理から成り立っています。
バンドラーは、大概、開発時に使うサーバ機能(開発サーバ)も提供します。この開発サーバで、開発効率の向上に有用な機能の一つがHMR(Hot Module Replacement)です。HMRは、動的にモジュールを差し替える仕組みで、ソースコードの変更に伴うビルド処理を省略し、変更を即座にブラウザ画面に反映させます。ソースコードを変更するたびに、開発サーバを再起動したり、ビルドを再実行したりする必要もなくなるので、開発効率がアップします。
JavaScript関連のサーベイであるState of JavaScriptの2023年版において、ビルドツールのランキングの中からいくつかのバンドラーをピックアップして紹介します。あらかじめ、以下にバンドラーの比較表をまとめておきます(CJM=CommonJS Modules、ESM=ES Mocules)。
Webpackは、2012年に誕生したバンドラーのルーツとも言える存在です。Tobias Koppers氏らによってリリースされました。Node.js環境で動作します。Webpackを一言で表すと、実績から来る安定性と言えます。ほとんどの機能を備えていて、かつ導入実績が多いことからエコシステムも充実しており、安心して使えるバンドラーと言えます。Webpackは非常に多機能である反面、利用を始めるまでに細かな設定が必要とされ、他のバンドラーの登場に伴い利用を避けられることもあります。
WebpackはES6以前のリリースであるので、CommonJS Modulesを基本としていますが、ES Modulesにも対応しています。なお、設定についてはWebpack 4で簡略化され、とりあえず設定ファイルがない状態でも既定値によるビルドが可能になっています。ただし、目的の動作を得るためには種々の設定が必要な点には変わりありません。
Rollupは、2015年にRich Harris氏によってリリースされました。最大の特徴は、ES6ベースであることです。ES6ベースであるので、モジュールの依存関係の解析が行いやすくなり、ムダな読み込みや解析を最小限に抑えられます。
強力で効率のよいTree Shakingをサポートしており、デッドコードの除去(Dead Code Elimination; DCE)度合いを細かく調整可能です。
ビルド成果物の効率がよいことから、後述のViteのリリースビルドに採用されています。
Parcelは、2017年にDevon Govett氏によってリリースされた比較的新しいバンドラーです。設定ファイルが不要のゼロコンフィグアプローチを採用しており、導入時の設定が不要なため、初心者に易しい設計となっています。
ビルドについては、JavaScriptコードによって実行されるのはWebpackと同様ですが、ワーカープロセスを使ったマルチコアコンパイルによりビルド速度が向上しています。また、ファイルシステム上に置かれるキャッシュによっても高速化が図られているなど、導入のしやすさだけではない特徴を持っています。
JavaScript、CSS、HTMLの変換が組み込みのBabel、PostCSS、PostHTMLでサポートされる点でも初心者に優しくなっています。また、HTMLなどのJavaScript以外のファイルをエントリポイントに指定可能で、エラーログが親切なのもParcelならではの機能と言えます。
esbuildは、2020年にEvan Wallace氏によってリリースされた新しいバンドラーです。他のバンドラーがスクリプト言語であるJavaScriptで記述されているのに対し、esbuildはプリコンパイル型言語のGoで記述されており、言語の特性を生かした並列処理と共有メモリの仕組みにより、キャッシュなしの極めて高速なビルドを特徴としています(公式サイトでもここをアピールしています)。
ソースマップの生成をサポートしているのもesbuildの特徴です。ソースマップとは、コンパイル前後のコードの対応をJSON形式で表したものです。ソースマップをサポートするブラウザ(Chromeなど)であれば、実行時にコンパイル前のソースを確認できてデバッグなどの効率が向上します。
esbuildでは、TypeScriptを直接サポートしますが、型チェックは行われないという制約があります。このため、別途型チェックを実行した後、ビルドするなどの手間が必要です。開発サーバもソースコードの変更監視が行われないので、別途ウォッチツールを組み合わせる必要があります。この他、CSSモジュールに非対応であったり、コード分割がサポートされなかったりするなど、速度面以外の機能は他のバンドラーに見劣りするように見えますが、速度面の特性を生かして、後述のViteでは開発時のプリコンパイルに採用されています。
esbuildは、本稿作成時点でバージョン1に達していないので、リリースプロダクトに採用する場合には注意が必要です。
ここまでバンドラーを紹介してきましたが、脱バンドラーとも言える動きもあります。最後に、この動きを踏まえたImport MapsとViteを紹介します。
Import Mapsは、バンドラーとは異なるアプローチでモジュールを利用する仕組みです。ES Modulesでは、モジュールをインポートするimport文に、「import foo from “https://hoge.com/foo.js”;」のようにモジュールの場所をURIで指定することができます。
しかしながらこの方法は、モジュールの場所をハードコードすることになるので、特に外部モジュールを参照する際には保守性の低下を招きます。そこで、モジュールのエイリアス名とその実体の対応表を定義し、import文にはそのエイリアス名のみを記述すればよいようにするのが、Import Mapsです。外部のモジュールを直接利用できるES Modulesのメリットに加えて、その名前を抽象化して保守性を向上させることができます。
具体的には、type属性に“importmap”を指定した<script>要素に、「モジュール指定マップ」と呼ばれるJSONオブジェクトを含めることで対応を定義します。JSONオブジェクトは、以下のように“imports”キーを含み、値としてエイリアス名と実体の場所を複数指定していきます。
<script type="importmap"> { "imports": { "foo": "https://hoge.com/foo.js", .... } } </script>
ブラウザは、モジュール指定マップを読み込むことでエイリアス名と実体の対応を把握し、import文に指定されるエイリアス名を実体に反映します。
主要なブラウザがImport Mapsをサポートし、HTTP/2による通信も一般的になってきたことから、バンドラーのメリットが相対的に低下して、Import Mapsを利用する動きが広がっています。Ruby on Rails 7でサポートされて話題となったほか、JavaScriptランタイムのDenoもImport Mapsをサポートしています。
Viteは、バンドル不要を打ち出したことで最近注目されているビルドツールです。2020年に、Vue.jsの作者であるEvan You氏によってリリースされました。名前は、フランス語の「vite(ヴィート、速く)」からきていると言われています。あらゆる局面で速く!ということをテーマに、従来のビルドツールにはなかったアプローチが多数取り込まれています。前述のサーベイでも、2021年から急激にUsageを伸ばしているのがViteです。
従来のビルドツールには、プロジェクトが大きくなってくるとバンドルに時間がかかる、開発サーバの起動に時間がかかる、といった問題がありました。そこでViteは、ES Modulesの機能を最大限に利用し、バンドルせずにモジュールを直接利用するというアプローチをとっています。これが、Viteがノーバンドルと呼ばれるゆえんです。
ただし、バンドルを全くしないわけではなく、ライブラリなど更新されることがないモジュールについては、esbuildを使ったプリコンパイルが実施されます。つまり、開発中に頻繁に更新されるファイルは直接、更新されないものはバンドルでと使い分けるわけです。
プロダクションリリースには、Rollupが利用されます。つまり、リリース時にはRollupにより最適化された成果物を公開できる、というわけです。なぜなら、公開時に最も求められるのは読み込みと実行の速度であるからです。
Viteは、ES Modulesとバンドラーのいいとこ取りで、他のバンドラーも活用しながら最大限のパフォーマンスを打ち出すビルドツールと言えます。
今回は、フロントエンドアプリの配布に欠かせない「バンドラー」を紹介しました。本記事をきっかけに興味を持ったバンドラーがあれば、ぜひ深掘りしていただきたいと思います。
関連記事
人気記事