browserify、grunt、gulp、parcel、rollup、webpack は、JavaScript アプリケーションの構築プロセスを管理するための代表的なツール群です。これらは歴史的な進化を反映しており、役割が明確に分かれています。
browserify と webpack、rollup、parcel は「モジュールバンドラー」に分類され、複数のファイルや依存関係を単一のファイル(または少数のファイル)に結合し、ブラウザで実行できるように変換します。一方、grunt と gulp は「タスクランナー」であり、ビルド、圧縮、テスト実行など、開発ワークフローにおける様々な自動化タスクを管理します。
近年のトレンドとしては、設定が不要で高速な parcel や、ライブラリ開発に特化した rollup、大規模アプリケーション向けの webpack が主流です。grunt と gulp は依然として特定のレガシープロジェクトや複雑なパイプライン処理で使われますが、モダンなフロントエンド構築においてはバンドラー機能が統合されたツールへ移行する傾向にあります。
フロントエンド開発において、コードをどのようにまとめ、最適化し、配信するかはプロジェクトの成否を左右します。browserify、grunt、gulp、parcel、rollup、webpack は、それぞれ異なる時代背景と設計思想を持って登場しました。これらを正しく理解し、プロジェクトの規模や要件に合わせて選定することは、エンジニアリングの質を高める上で不可欠です。
本稿では、これらのツールを「タスクランナー」と「モジュールバンドラー」という 2 つの軸で整理し、具体的なコード例を通じて技術的な違いとトレードオフを解説します。
まず大前提として、これらのツールは 2 つの異なるカテゴリに属します。
grunt, gulp): 「ファイルをコピーする」「画像を圧縮する」「テストを実行する」といった個別のタスクを定義し、実行順序を管理します。browserify, webpack, rollup, parcel): import や require で繋がれた複数のソースファイルを解析し、ブラウザが理解できる単一のファイル(バンドル)に結合します。現代の開発では、バンドラーがタスクランナーの機能(圧縮、変換など)も内包する傾向にあり、境界は曖昧になっていますが、根本的なアプローチの違いを理解しておく必要があります。
バンドラーごとの最大の違いは、「どのようにファイルを読み込み、結合するか」という点です。
browserify: CommonJS のための先駆者browserify は、Node.js で使われる require() 構文をブラウザで動作させるために誕生しました。ES Modules (import/export) への対応はプラグイン依存であり、現代の標準からは外れています。
// browserify: CommonJS スタイル
// entry.js
const math = require('./math');
console.log(math.add(2, 3));
// 実行コマンド
// browserify entry.js -o bundle.js
webpack: 何でも扱える万能エンジンwebpack は、JavaScript だけでなく CSS、画像、フォントなど全てを「モジュール」として扱います。ローダー(変換器)とプラグインの組み合わせで、あらゆる形式のファイルをバンドルに含めることができます。
// webpack: 多様なモジュール形式をサポート
// webpack.config.js
module.exports = {
entry: './src/index.js',
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.png$/, type: 'asset/resource' }
]
}
};
// src/index.js
import './style.css';
import logo from './logo.png';
console.log('App loaded');
rollup: ライブラリ開発に特化した最適化rollup は、ES Modules の静的解析を得意とし、使われていないコードを削除する「Tree Shaking」に非常に優れています。生成されるコードがシンプルで、ライブラリ開発者に愛用されています。
// rollup: ES Modules 重視
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
}
};
// src/main.js
import { add } from './math.js';
// 使わない関数は自動的に削除される
export const result = add(1, 2);
parcel: 設定不要の自動解決parcel は、エントリーポイント(通常は HTML ファイル)を指定するだけで、内部で依存関係を自動的に追跡し、バンドルします。設定ファイルが不要な点が最大の特徴です。
<!-- parcel: HTML をエントリーポイントに -->
<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<script src="./index.js"></script>
</body>
</html>
<!-- index.js -->
import './styles.css';
console.log('Parcel auto-bundled');
// 実行コマンド
// parcel index.html
タスクランナーである grunt と gulp は、バンドル以外の処理(ビルド前の整理、デプロイなど)をどのように扱うかで差別化されます。
grunt: 設定による宣言的アプローチgrunt は、Gruntfile 内でタスクごとの設定オブジェクトを定義します。処理の流れは設定ファイルに記述され、コードとしての自由度は低めですが、構造が明確です。
// grunt: 設定ベース
// Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
uglify: {
target: {
files: {
'dist/app.min.js': ['src/app.js']
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['uglify']);
};
gulp: コードによるストリーム処理gulp は、パイプ(pipe)を使ってファイルストリームをつなぐことで、タスクをコードとして記述します。中間ファイルをディスクに書き出さずにメモリ上で処理できるため、高速で柔軟です。
// gulp: ストリームベースのパイプライン
// gulpfile.js
const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
function minify() {
return src('src/*.js')
.pipe(uglify())
.pipe(dest('dist'));
}
exports.default = minify;
技術の進化に伴い、一部のツールは新規プロジェクトでの利用が推奨されなくなっています。
browserify の位置づけbrowserify は歴史的に重要なツールですが、現在は新規プロジェクトでの使用は推奨されません。ES Modules への対応がネイティブではなく、コード分割(Code Splitting)やホットリロードなどの現代機能を実装するには複雑な設定が必要だからです。既存のレガシーコードを維持する場合を除き、webpack や vite(Rollup ベース)などのモダンなバンドラーへ移行すべきです。
grunt と gulp の現在grunt と gulp も、多くのビルドタスクが webpack や vite、rollup に統合されたことで、単独で使われる機会は減りました。ただし、以下のようなケースでは依然として有効です。
gulp: 画像の最適化、CSS プリプロセッサのコンパイル、フォントのサブセット化など、ファイル変換パイプラインが複雑で、バンドラーの機能だけでは扱いにくい場合。grunt: 非常に古いプロジェクトの保守を行っており、設定資産が既に整っている場合。新規プロジェクトでは、これらのタスクも npm scripts で直接ツールを呼び出すか、バンドラーのプラグインとして統合する方がシンプルです。
各ツールがどのように主要機能を実装しているかを比較します。
大規模アプリでは、コードを分割して必要な部分だけを読み込むことが重要です。
webpack: 動的 import() を自動検知し、自動的にチャンクを作成します。
// webpack: 動的インポートで自動分割
const module = await import('./heavy-module.js');
rollup: manualChunks 設定で明示的に分割点を指定する必要があります。
// rollup: 手動設定
export default {
output: {
manualChunks: {
vendor: ['lodash', 'axios']
}
}
};
parcel: 動的 import() を検知して自動分割しますが、細かな制御は困難です。
// parcel: 自動分割(設定不要)
const module = await import('./heavy-module.js');
browserify: 標準機能としては提供されておらず、factor-bundle などのプラグインが必要で複雑です。
// browserify: プラグイン依存(例: factor-bundle)
// 複雑な CLI 設定が必要となり、現代的な DX とは言えません
grunt / gulp: 単体では機能せず、webpack-stream などでバンドラーをラップして実現します。コード変更時にページをリロードせず反映させる機能です。
webpack: webpack-dev-server を設定する必要があります。
// webpack: devServer 設定
module.exports = {
devServer: {
hot: true
}
};
parcel: コマンド一つで標準搭載されています。
# parcel: 標準機能
parcel src/index.html
rollup: 標準では非搭載。rollup-plugin-serve や livereload などのプラグインを組み合わせて構築します。
// rollup: プラグイン追加が必要
import serve from 'rollup-plugin-serve';
plugins: [serve({ open: true, port: 3000 })]
browserify: watchify などの外部ツールと組み合わせる必要があります。
# browserify: 外部ツール併用
watchify entry.js -o bundle.js -v
grunt / gulp: grunt-contrib-connect や browser-sync などを別途設定して実現します。ツール選定は「銀の弾丸」を探すことではなく、プロジェクトの要件とトレードオフを理解することです。
webpack が依然として最強の選択肢です。エコシステムが豊富で、複雑なコード分割やアセット管理にも対応できます。rollup を選択してください。Tree Shaking による出力サイズの最小化と、クリーンなバンドル生成が得意です。parcel が最適です。設定の手間がなく、すぐに開発を始められます。browserify、grunt、gulp は、既存の資産がある場合にのみ維持し、新規採用は避けるべきです。現代のフロントエンド開発では、これらのツールを単独で使うだけでなく、Vite(Rollup ベースの高速開発サーバー)や Turbopack(Webpack 開発者による次世代ツール)のような、より開発体験(DX)を重視した新しい選択肢も視野に入れる必要があります。しかし、基礎となるこれらのツールの特性を理解していれば、どのような技術スタックに対しても適切なアーキテクチャ判断を下せるでしょう。
大規模なエンタープライズアプリケーションや、複雑なコード分割、アセット管理、ローダー生態系を必要とする場合に業界標準として選択されます。設定の学習コストは高いものの、あらゆるユースケースに対応できる柔軟性と、巨大なプラグインエコシステムを持っています。
ファイルストリームに基づく複雑な変換パイプライン(画像最適化、CSS 前処理など)を手動で制御したい場合に適しています。コードとしてタスクを記述できるため柔軟性は高いですが、モダンなバンドラーがこれらの機能を取り込んでいるため、あえて単独で採用するメリットは限定的です。
設定ファイルを一切書かずに、ゼロコンフィグで迅速にプロトタイプや中小規模のアプリを構築したい場合に最適です。HTML エントリーポイントから自動で依存関係を解決し、HMR(高速モジュール置き換え)も標準搭載しています。細かいチューニングが必要になる大規模プロジェクトには向きません。
レガシーな CommonJS プロジェクトを維持・移行する場合にのみ選択を検討してください。現代の ES Modules 標準やコード分割機能には対応しておらず、新規プロジェクトでの採用は推奨されません。既存の npm モジュールをブラウザで動かすだけの単純な要件であれば有効ですが、拡張性は低いです。
設定ファイル(Gruntfile)による宣言的な設定を好む場合や、非常に古いプロジェクトの保守が必要な場合にのみ使用します。タスクごとの設定が冗長になりやすく、大規模化するとメンテナンスが困難になるため、新規プロジェクトでは npm scripts や他のツールへの移行を強く推奨します。
npm ライブラリやフレームワークなど、Tree Shaking を効かせて高効率なバンドルを生成したい場合に首选されます。ES Modules 形式の入出力に強く、生成されるコードが非常にクリーンです。ただし、複雑なコード分割やアセット管理には webpack に比べて追加設定が必要になることがあります。
Webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
Install with npm:
npm install --save-dev webpack
Install with yarn:
yarn add webpack --dev
Webpack is a bundler for modules. The main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
TL;DR
Check out webpack's quick Get Started guide and the other guides.
Webpack supports all browsers that are ES5-compliant (IE8 and below are not supported).
Webpack also needs Promise for import() and require.ensure(). If you want to support older browsers, you will need to load a polyfill before using these expressions.
Webpack has a rich plugin interface. Most of the features within webpack itself use this plugin interface. This makes webpack very flexible.
Webpack can generate HTML pages and extract CSS files itself, both experimental — see what that covers, and what still needs a plugin, for CSS and HTML.
| Name | Status | Install Size | Description |
|---|---|---|---|
| compression-webpack-plugin | Prepares compressed versions of assets to serve them with Content-Encoding | ||
| html-bundler-webpack-plugin | Renders a template (EJS, Handlebars, Pug) with referenced source asset files into HTML. | ||
| pug-plugin | Renders Pug files to HTML, extracts JS and CSS from sources specified directly in Pug. |
Webpack enables the use of loaders to preprocess files. This allows you to bundle any static resource way beyond JavaScript. You can easily write your own loaders using Node.js.
Loaders are activated by using loadername! prefixes in require() statements,
or are automatically applied via regex from your webpack configuration.
JavaScript, JSON and assets need no loader, and CSS and HTML have experimental built-in support — but preprocessors and template engines keep their loaders.
| Name | Status | Install Size | Description |
|---|---|---|---|
| Loads and transpiles a CSON file |
| Name | Status | Install Size | Description |
|---|---|---|---|
| Loads ES2015+ code and transpiles to ES5 using Babel | |||
| Loads TypeScript like JavaScript | |||
| Loads CoffeeScript like JavaScript |
| Name | Status | Install Size | Description |
|---|---|---|---|
| Compiles Pug to a function or HTML string, useful for use with Vue, React, Angular | |||
| Compiles Markdown to HTML | |||
| Loads and transforms a HTML file using PostHTML | |||
| Compiles Handlebars to HTML |
| Name | Status | Install Size | Description |
|---|---|---|---|
| Loads and compiles a LESS file | |||
| Loads and compiles a Sass/SCSS file | |||
| Loads and compiles a Stylus file | |||
| Loads and transforms a CSS/SSS file using PostCSS |
Webpack uses async I/O and has multiple caching levels. This makes webpack fast and incredibly fast on incremental compilations.
Webpack supports ES2015+, CommonJS and AMD modules out of the box. It performs clever static analysis on the AST of your code. It even has an evaluation engine to evaluate simple expressions. This allows you to support most existing libraries out of the box.
Webpack allows you to split your codebase into multiple chunks. Chunks are loaded asynchronously at runtime. This reduces the initial loading time.
Webpack can do many optimizations to reduce the output size of your JavaScript by deduplicating frequently used modules, minifying, and giving you full control of what is loaded initially and what is loaded at runtime through code splitting. It can also make your code chunks cache friendly by using hashes.
If you're working on webpack itself, or building advanced plugins or integrations, the tools below can help you explore internal mechanics, debug plugin life-cycles, and build custom tooling.
| Name | Status | Description |
|---|---|---|
| tapable-tracer | Traces tapable hook execution in real-time and collects structured stack frames. Can export to UML for generating visualizations. |
We want contributing to webpack to be fun, enjoyable, and educational for anyone, and everyone. We have a vibrant ecosystem that spans beyond this single repo. We welcome you to check out any of the repositories in our organization or webpack-contrib organization which houses all of our loaders and plugins.
Contributions go far beyond pull requests and commits. Although we love giving you the opportunity to put your stamp on webpack, we also are thrilled to receive a variety of other contributions including:
To get started have a look at our documentation on contributing.
For when your change reaches npm, see RELEASE_SCHEDULE.md — patch releases go out as soon as possible, minor releases every 4 weeks on Thursday.
If you create a loader or plugin, we would <3 for you to open source it, and put it on npm. We follow the x-loader, x-webpack-plugin naming convention.
We consider webpack to be a low-level tool used not only individually but also layered beneath other awesome tools. Because of its flexibility, webpack isn't always the easiest entry-level solution, however we do believe it is the most powerful. That said, we're always looking for ways to improve and simplify the tool without compromising functionality. If you have any ideas on ways to accomplish this, we're all ears!
If you're just getting started, take a look at our new docs and concepts page. This has a high level overview that is great for beginners!!
If you have discovered a 🐜 or have a feature suggestion, feel free to create an issue on GitHub.
For information about the governance of the webpack project, see GOVERNANCE.md.
This webpack repository is maintained by the Core Working Group.
Most of the core team members, webpack contributors and contributors in the ecosystem do this open source work in their free time. If you use webpack for a serious task, and you'd like us to invest more time on it, please donate. This project increases your income/productivity too. It makes development and applications faster and it reduces the required bandwidth.
This is how we use the donations:
Before we started using OpenCollective, donations were made anonymously. Now that we have made the switch, we would like to acknowledge these sponsors (and the ones who continue to donate using OpenCollective). If we've missed someone, please send us a PR, and we'll add you to this list.
Become a gold sponsor and get your logo on our README on GitHub with a link to your site.
Become a silver sponsor and get your logo on our README on GitHub with a link to your site.
Become a bronze sponsor and get your logo on our README on GitHub with a link to your site.
Become a backer and get your image on our README on GitHub with a link to your site.
(In chronological order)