gulp vs browserify vs parcel vs rollup vs webpack
現代のフロントエンドビルドツールとバンドラーの選定
gulpbrowserifyparcelrollupwebpack類似パッケージ:

現代のフロントエンドビルドツールとバンドラーの選定

これらのツールは JavaScript アプリケーションの構築プロセスを支える重要なインフラです。webpackrollup はモジュールを束ねるバンドラーとして機能し、gulp はタスク自動化を専門とし、parcel は設定不要のビルド体験を提供します。browserify は歴史的に重要な CommonJS バンドラーですが、現在は維持モードに近い状態です。プロジェクトの規模や目的に応じて、適切なツールを選ぶことが開発効率とパフォーマンスに直結します。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
gulp2,007,24132,98611.2 kB3410ヶ月前MIT
browserify1,896,95914,725363 kB3782年前MIT
parcel044,03844 kB5902ヶ月前MIT
rollup026,2662.83 MB60117日前MIT
webpack065,8356.13 MB2019時間前MIT

フロントエンドビルドツール完全比較:webpack vs rollup vs parcel vs gulp vs browserify

現代のフロントエンド開発において、コードをどのように束ねて配信するかは重要な決定です。webpackrollupparcelgulpbrowserify はそれぞれ異なる歴史と目的を持って誕生しました。これらを正しく理解し、プロジェクトに合ったツールを選ぶことは、長期的なメンテナンス性に影響します。ここでは、実際の設定コードや動作の違いを通して、各ツールの特徴を比較します。

⚙️ 設定ファイルの書き方:明示的 vs 自動検出

ツールごとに設定の考え方が異なります。明示的に書くほど制御できますが、手間も増えます。

webpack は設定ファイルを明示的に書く必要があります。

  • webpack.config.js にエントリーポイントや出力先を定義します。
  • 複雑な設定も可能ですが、初期コストがかかります。
// webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: __dirname + '/dist'
  }
};

rollup も設定ファイルを書きますが、構造はシンプルです。

  • rollup.config.js で入力と出力フォーマットを指定します。
  • ライブラリ出力に適した設定が用意されています。
// rollup.config.js
export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'es'
  }
};

parcel は設定ファイルが基本的に不要です。

  • エントリーポイントとなる HTML ファイルを指定するだけで動きます。
  • 内部で自動的に最適化されます。
// package.json
{
  "scripts": {
    "dev": "parcel src/index.html",
    "build": "parcel build src/index.html"
  }
}

gulp はタスク定義ファイルを使います。

  • gulpfile.js に処理の流れを関数で書きます。
  • バンドルというより、処理のパイプラインを定義します。
// gulpfile.js
const { src, dest } = require('gulp');
function build() {
  return src('src/*.js').pipe(dest('dist'));
}
exports.build = build;

browserify は CLI または API で指定します。

  • 設定ファイルというより、コマンドラインオプションで制御します。
  • 単純なバンドルには手軽ですが、複雑化すると管理が難しいです。
# CLI usage
browserify src/index.js -o dist/bundle.js

📦 モジュールの扱い方:CommonJS vs ESM

JavaScript のモジュール形式への対応は、ツールの得意不得意が分かれるポイントです。

webpack は CommonJS と ESM の両方を混在させて扱えます。

  • 古い npm パッケージと新しいコードを一緒に使えます。
  • 変換処理を自動で行うため、開発者は意識しなくて済みます。
// webpack handles both seamlessly
const lib = require('some-lib'); // CommonJS
import utils from './utils'; // ESM

rollup は ESM を第一に考えて設計されています。

  • CommonJS も使えますが、プラグインが必要です。
  • 出力コードが非常にクリーンで、ライブラリ配布に適しています。
// rollup prefers ESM
import utils from './utils';
export default function main() { /*...*/ }

parcel も両方を自動で処理します。

  • 設定なしで ESM と CommonJS を検知してバンドルします。
  • 内部で Babel などを自動適用するため、設定の手間がありません。
// parcel auto-detects
import React from 'react';
const mod = require('./module');

gulp 自体はモジュール形式を変換しません。

  • バンドル機能がないため、browserify や webpack と組み合わせて使います。
  • 変換処理はプラグインに依存します。
// gulp needs plugins for bundling
const browserify = require('browserify');
// gulp task pipes files through browserify

browserify は CommonJS をブラウザで動かすために作られました。

  • ESM のサポートは限定的です。
  • 現代の ESM ベースのプロジェクトには不向きです。
// browserify focuses on CommonJS
const dep = require('dependency');
module.exports = function() { /*...*/ };

🖼️ アセット管理:画像と CSS の扱い

JavaScript 以外のファイルをどう扱うかも重要な選定基準です。

webpack はローダーを使ってあらゆるファイルを扱えます。

  • CSS や画像も JavaScript のように import できます。
  • 設定は複雑になりますが、統一された管理が可能です。
// webpack.config.js
module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  }
};

rollup はプラグインでアセットを扱います。

  • 標準機能ではないため、設定が必要です。
  • ライブラリ開発では JS 出力のみで済むことが多いです。
// rollup.config.js
import postcss from 'rollup-plugin-postcss';
export default {
  plugins: [postcss()]
};

parcel は最初からアセット対応しています。

  • CSS や画像を import すると、自動で最適化して出力します。
  • 追加設定が不要で、すぐに使えます。
// parcel handles assets automatically
import './style.css';
import logo from './logo.png';

gulp はストリーム処理でアセットを移動または変換します。

  • CSS の結合や画像の圧縮などをタスクとして定義します。
  • バンドルとは別の工程として扱われることが多いです。
// gulpfile.js
const cssmin = require('gulp-cssmin');
function styles() {
  return src('src/*.css').pipe(cssmin()).pipe(dest('dist'));
}

browserify はアセット処理が苦手です。

  • プラグイン(transform)を使わないと CSS などを扱えません。
  • 設定が煩雑になりがちです。
// browserify needs transforms
browserify('main.js')
  .transform('css-modulesify')
  .bundle();

🛠️ 現在のステータスと推奨事項

ツールのメンテナンス状況は、長期的なプロジェクトにおいてリスク管理に関わります。

webpack は現在も活発に開発されています。

  • 業界標準として広く採用されており、情報も豊富です。
  • 大規模プロジェクトで最も信頼性が高い選択肢です。

rollup も積極的に更新されています。

  • ライブラリ開発のデファクトスタンダードです。
  • Vite などのモダンなツールの基盤としても使われています。

parcel はバージョン 2 になり安定しました。

  • 零設定開発を求めている場合に有力な候補です。
  • 機能が成熟しており、プロダクション利用も可能です。

gulp はメンテナンスされていますが、役割が変わりました。

  • バンドラーとしては使われず、タスクランナーとして残っています。
  • npm scripts で代用できる場合は、導入を検討する必要はありません。

browserify は事実上のレガシーツールです。

  • 公式に非推奨と明記されていませんが、更新頻度は低いです。
  • 新規プロジェクトでの採用は避けるべきです。

💡 結論:どれを選ぶべきか

それぞれのツールには明確な役割があります。目的に合わせて選ぶことが重要です。

  • アプリケーション開発webpack または parcel が適しています。複雑なら webpack、手軽さなら parcel です。
  • ライブラリ開発rollup 一択です。出力コードの品質が最も優れています。
  • タスク自動化gulp よりも npm scriptsMakefile を検討してください。それでも不足する場合に gulp です。
  • レガシー対応browserify は既存システムの維持以外では使いません。

ツール選びは正解が一つではありません。プロジェクトの要件とチームのスキルセットに合わせて、最適な組み合わせを選んでください。

選び方: gulp vs browserify vs parcel vs rollup vs webpack

  • gulp:

    ファイルの変換やサーバー起動など、ビルド以外のタスク自動化を必要とする場合に選びます。バンドル機能単体ではなく、ワークフロー全体を管理したい時に有効です。バンドル自体は webpack や rollup に任せ、gulp はその前後の処理に使います。

  • browserify:

    小さなプロジェクトや CommonJS のみの環境で動作させる場合に適しています。しかし、現代の機能や最適化機能は不足しているため、新規の大規模プロジェクトでは避けるべきです。既存のレガシーコードを維持する必要がある場合を除き、他の選択肢を検討してください。

  • parcel:

    設定ファイルを一切書きたくない場合や、プロトタイプを素早く作成したい時に最適です。標準機能で多くの形式に対応しており、学習コストが低いのが特徴です。細かい制御が必要になった時に壁にぶつかる可能性があります。

  • rollup:

    JavaScript ライブラリやフレームワークを開発する際に最も適しています。ツリーシェイキング機能に優れており、クリーンな ESM 出力を生成できます。アプリケーション全体をビルドするよりも、部品を作るのに適しています。

  • webpack:

    複雑な依存関係や多様なアセットを扱う大規模アプリケーションに最適です。ローダーやプラグインによる拡張性が非常に高く、細かな制御が必要な場合に選ばれます。設定の学習コストは高いですが、その分柔軟性があります。

gulp のREADME

The streaming build system

NPM version Downloads Build Status Coveralls Status

What is gulp?

  • Automation - gulp is a toolkit that helps you automate painful or time-consuming tasks in your development workflow.
  • Platform-agnostic - Integrations are built into all major IDEs and people are using gulp with PHP, .NET, Node.js, Java, and other platforms.
  • Strong Ecosystem - Use npm modules to do anything you want + over 3000 curated plugins for streaming file transformations.
  • Simple - By providing only a minimal API surface, gulp is easy to learn and simple to use.

Installation

Follow our Quick Start guide.

Roadmap

Find out about all our work-in-progress and outstanding issues at https://github.com/orgs/gulpjs/projects.

Documentation

Check out the Getting Started guide and API docs on our website!

Excuse our dust! All other docs will be behind until we get everything updated. Please open an issue if something isn't working.

Sample gulpfile.js

This file will give you a taste of what gulp does.

var gulp = require('gulp');
var less = require('gulp-less');
var babel = require('gulp-babel');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var cleanCSS = require('gulp-clean-css');
var del = require('del');

var paths = {
  styles: {
    src: 'src/styles/**/*.less',
    dest: 'assets/styles/'
  },
  scripts: {
    src: 'src/scripts/**/*.js',
    dest: 'assets/scripts/'
  }
};

/* Not all tasks need to use streams, a gulpfile is just another node program
 * and you can use all packages available on npm, but it must return either a
 * Promise, a Stream or take a callback and call it
 */
function clean() {
  // You can use multiple globbing patterns as you would with `gulp.src`,
  // for example if you are using del 2.0 or above, return its promise
  return del([ 'assets' ]);
}

/*
 * Define our tasks using plain functions
 */
function styles() {
  return gulp.src(paths.styles.src)
    .pipe(less())
    .pipe(cleanCSS())
    // pass in options to the stream
    .pipe(rename({
      basename: 'main',
      suffix: '.min'
    }))
    .pipe(gulp.dest(paths.styles.dest));
}

function scripts() {
  return gulp.src(paths.scripts.src, { sourcemaps: true })
    .pipe(babel())
    .pipe(uglify())
    .pipe(concat('main.min.js'))
    .pipe(gulp.dest(paths.scripts.dest));
}

function watch() {
  gulp.watch(paths.scripts.src, scripts);
  gulp.watch(paths.styles.src, styles);
}

/*
 * Specify if tasks run in series or parallel using `gulp.series` and `gulp.parallel`
 */
var build = gulp.series(clean, gulp.parallel(styles, scripts));

/*
 * You can use CommonJS `exports` module notation to declare tasks
 */
exports.clean = clean;
exports.styles = styles;
exports.scripts = scripts;
exports.watch = watch;
exports.build = build;
/*
 * Define default task that can be called by just running `gulp` from cli
 */
exports.default = build;

Use latest JavaScript version in your gulpfile

Gulp provides a wrapper that will be loaded in your ESM code, so you can name your gulpfile as gulpfile.mjs or with "type": "module" specified in your package.json file.

And here's the same sample from above written in ESNext.

import { src, dest, watch } from 'gulp';
import less from 'gulp-less';
import babel from 'gulp-babel';
import concat from 'gulp-concat';
import uglify from 'gulp-uglify';
import rename from 'gulp-rename';
import cleanCSS from 'gulp-clean-css';
import del from 'del';

const paths = {
  styles: {
    src: 'src/styles/**/*.less',
    dest: 'assets/styles/'
  },
  scripts: {
    src: 'src/scripts/**/*.js',
    dest: 'assets/scripts/'
  }
};

/*
 * For small tasks you can export arrow functions
 */
export const clean = () => del([ 'assets' ]);

/*
 * You can also declare named functions and export them as tasks
 */
export function styles() {
  return src(paths.styles.src)
    .pipe(less())
    .pipe(cleanCSS())
    // pass in options to the stream
    .pipe(rename({
      basename: 'main',
      suffix: '.min'
    }))
    .pipe(dest(paths.styles.dest));
}

export function scripts() {
  return src(paths.scripts.src, { sourcemaps: true })
    .pipe(babel())
    .pipe(uglify())
    .pipe(concat('main.min.js'))
    .pipe(dest(paths.scripts.dest));
}

 /*
  * You could even use `export as` to rename exported tasks
  */
function watchFiles() {
  watch(paths.scripts.src, scripts);
  watch(paths.styles.src, styles);
}
export { watchFiles as watch };

const build = gulp.series(clean, gulp.parallel(styles, scripts));
/*
 * Export a default task
 */
export default build;

Incremental Builds

You can filter out unchanged files between runs of a task using the gulp.src function's since option and gulp.lastRun:

const paths = {
  ...
  images: {
    src: 'src/images/**/*.{jpg,jpeg,png}',
    dest: 'build/img/'
  }
}

function images() {
  return gulp.src(paths.images.src, {since: gulp.lastRun(images)})
    .pipe(imagemin())
    .pipe(gulp.dest(paths.images.dest));
}

function watch() {
  gulp.watch(paths.images.src, images);
}

Task run times are saved in memory and are lost when gulp exits. It will only save time during the watch task when running the images task for a second time.

Want to contribute?

Anyone can help make this project better - check out our Contributing guide!