vite vs esbuild 徹底比較

vite の詳細esbuild の詳細
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

vite vs esbuild — どちらを選ぶべきか?徹底比較

1. 結論

アプリケーション開発のフルスタックな開発環境が必要なら vite、ライブラリのバンドルや既存ビルドパイプラインへの高速トランスパイラ組み込みなら esbuild を選んでください。 実は vite は内部で esbuild を利用しており、両者は「競合」というより「レイヤーが異なるツール」です。プロジェクトの要件に応じて、併用するケースも十分にあり得ます。


2. 比較表

観点viteesbuild
カテゴリ開発サーバー + ビルドツール(フレームワーク寄り)バンドラー / トランスパイラ / ミニファイア(低レベル寄り)
言語TypeScript + JavaScript(内部で Go 製 esbuild を利用)Go(ネイティブバイナリ)
バンドルサイズ(node_modules)約 40〜60 MB(プラグイン込み)約 9 MB
ビルド速度高速(本番ビルドは Rollup ベース)極めて高速(webpack 比で 10〜100 倍)
開発サーバー✅ HMR 付きの高機能サーバー内蔵❌ 簡易的な serve モードのみ
HMR(Hot Module Replacement)✅ フレームワーク対応の高精度 HMR❌ 非対応
プラグインシステム✅ Rollup 互換プラグイン + Vite 独自フック⚠️ プラグイン API はあるが限定的
TypeScript 対応✅ 設定不要でそのまま使える✅ ネイティブで高速トランスパイル
CSS / PostCSS✅ CSS Modules, PostCSS, Sass 等を標準サポート⚠️ CSS バンドルは可能だが機能は限定的
フレームワーク対応✅ React / Vue / Svelte / Solid 等の公式テンプレート❌ フレームワーク固有の処理は自前実装が必要
Code Splitting✅(Rollup ベースで柔軟)⚠️ 対応しているが設定の柔軟性は低い
Tree Shaking✅(Rollup の高精度 Tree Shaking)✅(高速だがやや粗い場合あり)
型チェック❌(トランスパイルのみ、tsc 別途必要)❌(トランスパイルのみ、tsc 別途必要)
学習コスト中(設定ファイルは直感的)低(API がシンプル)
週間ダウンロード数(2024年時点)約 1,500 万約 3,500 万(vite 経由の間接利用含む)
ライセンスMITMIT

3. それぞれの強み

vite の強み

  • オールインワンの開発体験: npm create vite@latest 一発で、開発サーバー・HMR・本番ビルド・プレビューサーバーがすべて揃います
  • フレームワークとの深い統合: React Fast Refresh、Vue SFC、Svelte コンパイルなどがプラグイン一つで動作します
  • Native ESM による高速な開発サーバー: 開発時はバンドルせず、ブラウザの ESM をそのまま活用するため、大規模プロジェクトでも起動が高速です
  • 豊富なエコシステム: Vitest(テスト)、VitePress(ドキュメント)、Nuxt / SvelteKit / Astro など主要メタフレームワークが Vite ベースです
  • 成熟したプラグインエコシステム: Rollup 互換プラグインがそのまま使えるため、選択肢が非常に豊富です

esbuild の強み

  • 圧倒的なビルド速度: Go で書かれたネイティブバイナリのため、JavaScript 製ツールとは桁違いの速度を実現します
  • シンプルな API: バンドル・トランスパイル・ミニファイという明確な責務に集中しており、設定が最小限です
  • 軽量: 依存が少なく、node_modules の肥大化を抑えられます
  • 汎用性: CLI・JavaScript API・Go API の 3 通りで利用でき、他ツールへの組み込みが容易です
  • ミニファイア単体としての利用: Terser の代替として、既存の webpack / Rollup パイプラインに組み込むだけでビルド時間を大幅短縮できます

4. コード例で比較

タスク: React + TypeScript アプリをビルドする

vite の場合

プロジェクト作成:

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install

vite.config.ts:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  build: {
    outDir: 'dist',
    sourcemap: true,
  },
  server: {
    port: 3000,
    open: true,
  },
})

src/App.tsx:

import { useState } from 'react'

export default function App() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <h1>vite + React + TypeScript</h1>
      <button onClick={() => setCount((c) => c + 1)}>
        count: {count}
      </button>
    </div>
  )
}

開発 & ビルド:

# 開発サーバー起動(HMR付き)
npm run dev

# 本番ビルド
npm run build

# ビルド結果のプレビュー
npm run preview

esbuild の場合

セットアップ:

mkdir my-app && cd my-app
npm init -y
npm install esbuild react react-dom
npm install -D @types/react @types/react-dom typescript

build.ts(ビルドスクリプト):

import * as esbuild from 'esbuild'

// --- 本番ビルド ---
async function build() {
  const result = await esbuild.build({
    entryPoints: ['src/index.tsx'],
    bundle: true,
    outdir: 'dist',
    minify: true,
    sourcemap: true,
    format: 'esm',
    splitting: true,
    target: ['es2020'],
    loader: {
      '.tsx': 'tsx',
      '.ts': 'ts',
    },
    define: {
      'process.env.NODE_ENV': '"production"',
    },
    metafile: true,
  })

  // バンドルサイズの解析
  const analysis = await esbuild.analyzeMetafile(result.metafile)
  console.log(analysis)
}

build().catch(() => process.exit(1))

watch.ts(開発用の簡易ウォッチ):

import * as esbuild from 'esbuild'

async function watch() {
  const ctx = await esbuild.context({
    entryPoints: ['src/index.tsx'],
    bundle: true,
    outdir: 'dist',
    format: 'esm',
    sourcemap: true,
    loader: {
      '.tsx': 'tsx',
      '.ts': 'ts',
    },
    define: {
      'process.env.NODE_ENV': '"development"',
    },
  })

  // ファイル変更を監視して自動リビルド
  await ctx.watch()

  // 簡易的な開発サーバー(HMR なし、ライブリロードのみ)
  const { host, port } = await ctx.serve({
    servedir: 'dist',
  })

  console.log(`Serving on http://${host}:${port}`)
}

watch().catch(() => process.exit(1))

src/App.tsx(同一コード):

import { useState } from 'react'

export default function App() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <h1>esbuild + React + TypeScript</h1>
      <button onClick={() => setCount((c) => c + 1)}>
        count: {count}
      </button>
    </div>
  )
}

開発 & ビルド:

# 開発(ウォッチ + 簡易サーバー)
npx tsx watch.ts

# 本番ビルド
npx tsx build.ts

比較ポイント

観点viteesbuild
セットアップ行数約 15 行(設定ファイルのみ)約 50 行(ビルド + ウォッチスクリプト)
HMR✅ React Fast Refresh 対応❌ フルリロードのみ
HTML 生成✅ 自動(index.html テンプレート)❌ 自前で用意が必要
環境変数.env ファイル対応define で手動設定

タスク: ライブラリをバンドルする(esbuild が得意な領域)

esbuild でユーティリティライブラリをビルド:

import * as esbuild from 'esbuild'

// CJS + ESM のデュアルパッケージビルド
async function buildLibrary() {
  const shared: esbuild.BuildOptions = {
    entryPoints: ['src/index.ts'],
    bundle: true,
    sourcemap: true,
    external: ['react', 'react-dom'], // peerDeps は外部化
    target: ['es2020'],
  }

  // ESM 形式
  await esbuild.build({
    ...shared,
    format: 'esm',
    outfile: 'dist/index.mjs',
  })

  // CJS 形式
  await esbuild.build({
    ...shared,
    format: 'cjs',
    outfile: 'dist/index.cjs',
  })

  console.log('Library build complete!')
}

buildLibrary()

ポイント: ライブラリのビルドでは、esbuild の「速くてシンプル」という特性が最大限に活きます。vite でもライブラリモード(build.lib)は提供されていますが、内部的には Rollup を使うため、esbuild ほどの速度は出ません。


5. どちらを選ぶべきか — ユースケース別の推奨

✅ vite を選ぶべきケース

ユースケース理由
SPA / MPA のアプリケーション開発HMR・開発サーバー・本番ビルドがオールインワン
React / Vue / Svelte を使うプロジェクトフレームワーク統合プラグインが成熟している
チーム開発で統一した開発環境が必要設定の規約化がしやすく、エコシステムが豊富
SSR / SSG を含むプロジェクトNuxt / SvelteKit / Astro など主要フレームワークが Vite ベース
CSS Modules / Sass / PostCSS を多用する設定不要で動作する

✅ esbuild を選ぶべきケース

ユースケース理由
npm パッケージ / ライブラリのビルド高速で設定がシンプル、CJS/ESM デュアル出力が容易
既存ビルドパイプラインの高速化ミニファイアやトランスパイラとして部分的に導入可能
CI/CD のビルド時間短縮圧倒的な速度で CI コストを削減
カスタムビルドツールの基盤JavaScript API / Go API で柔軟に組み込める
シンプルな静的サイトやスクリプトのバンドルフレームワーク不要な小規模プロジェクト

✅ 併用するケース(実は最も一般的)

vite を使う = esbuild も使っている

vite は内部で以下の用途に esbuild を利用しています。

  • 開発時の依存関係の事前バンドル(Pre-bundling)
  • TypeScript / JSX のトランスパイル
  • 本番ビルド時の CSS ミニファイ(デフォルト)
  • 本番ビルド時の JS ミニファイbuild.minify: 'esbuild' がデフォルト)

つまり、vite を選んだ時点で esbuild の恩恵は自動的に受けています。


6. まとめ

esbuild = エンジン(速さ・シンプルさ)
vite    = 車(エンジン + 快適装備 + フレームワーク統合)

**esb