Skip to content
⚠️ This article was written in 2021. Some content may be outdated.

フロントエンドビルドパフォーマンス最適化:Webpack から Vite へ

最近、いくつかのプロジェクトを Webpack から Vite に順次移行しましたが、ビルド速度の差は想像以上に大きいものでした。この記事では、ビルドパフォーマンス最適化のアプローチを、Webpack チューニングから Vite への乗り換え判断に至るまで整理します。

Webpack のボトルネックはどこか

Webpack が遅い理由の核心は、すべてがモジュールであり、モジュールはまずバンドルしてからでないと起動できない という点にあります。

dev server の起動:
1. エントリーファイルを解析
2. すべての import を再帰的に解決 → 完全な依存関係グラフを構築
3. すべてのモジュールをコンパイル(Babel + Loader チェーン)
4. bundle を生成
5. サーバーを起動

プロジェクトが大きくなると、ステップ 2-4 に 30秒〜2分 かかる可能性がある

Webpack のチューニング(どこまでパフォーマンスを絞り出せるか)

1. 検索範囲を絞り込む

javascript
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        include: path.resolve(__dirname, 'src'), // src のみ処理
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.js'], // 拡張子は書き省くが、列挙しすぎない
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
    // symlink の解決は不要
    symlinks: false,
  },
}

2. キャッシュ

javascript
module.exports = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              // 永続キャッシュを有効化(Webpack 5 組み込み)
              // ts-loader + transpileOnly で大幅高速化
              transpileOnly: true,
            },
          },
        ],
      },
    ],
  },
  // Webpack 5 永続キャッシュ
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename],
    },
  },
}

3. マルチスレッド

javascript
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // マルチスレッド圧縮
      }),
    ],
  },
  // 或者用 thread-loader
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: [
          'thread-loader', // 後続の loader を worker プールに配置
          'ts-loader',
        ],
      },
    ],
  },
}

4. DLL(古い方式、Webpack 5 では不要)

javascript
// Webpack 4 時代の方式:変更されない依存関係を事前バンドル
// Webpack 5 では cache.type: 'filesystem' で代替

Webpack チューニングの天井

ある中規模プロジェクト(200+ モジュール)での実測:

最適化項目時間
最適化なし45s
ts-loader transpileOnly28s
filesystem cache(2回目起動)8s
thread-loader22s
すべて最適化6s(2回目起動)

2回目起動の 6s が Webpack の限界であり、初回起動は依然として 20s+ かかります。

Vite:発想の転換

Vite の核となる考え方:開発環境ではバンドルせず、本番環境では Rollup を使用する

dev server の起動:
1. サーバーを起動(ほぼ瞬時)
2. ブラウザのリクエスト → 必要に応じて単一ファイルをコンパイル
3. 結果を返却

起動時間:< 1s
bash
npm create vite@latest my-app -- --template vue-ts
cd my-app
npm install
npm run dev   # < 1s 启动

Vite がなぜ速いか

typescript
// ブラウザが /src/main.ts をリクエスト
// Vite が返却:

// import { createApp } from 'vue'
// ↓ 変換後
import { createApp } from '/node_modules/.vite/deps/vue.js?v=abc123'

// 各依存関係は事前にビルド済み(esbuild)、各ファイルは個別にコンパイル
// アクセスしたモジュールだけがコンパイルされる
  • 依存関係の事前ビルド:esbuild(Go 言語で記述、JS より 10〜100 倍高速)
  • ソースコードのオンデマンドコンパイル:ESM + ブラウザのネイティブインポート
  • HMR:変更されたファイルのみをコンパイルし、依存関係グラフのサイズに依存しない

パフォーマンスベンチマーク

同一プロジェクト(Vue 3 + TypeScript、200+ コンポーネント):

指標Webpack 5(最適化後)Vite 2.x
初回起動22s0.8s
2回目起動(キャッシュ)6s0.3s
HMR2-5s< 100ms
プロダクションビルド45s30s
バンドルサイズ(gzip)186KB178KB

プロダクションビルドの差は大きくありませんが(Vite は Rollup を使用、Rollup の tree-shaking が優れている)、開発体験の差は非常に大きいです。

移行時の注意点

typescript
// 1. import には拡張子が必要(または resolve.extensions を設定)
import { ref } from 'vue'         // ✅ サードパーティパッケージは拡張子不要
import { useAuth } from './auth'  // ❌ Vite ではデフォルトで拡張子が必要
import { useAuth } from './auth.ts' // ✅

// vite.config.ts で緩和可能
export default defineConfig({
  resolve: {
    extensions: ['.ts', '.js', '.vue'], // 拡張子解決を追加
  },
})

// 2. 環境変数
// Webpack: process.env.NODE_ENV
// Vite: import.meta.env.MODE

// 3. 静的アセット
// Webpack: require('./logo.png') → URL
// Vite: import logo from './logo.png' → URL

// 4. CSS Modules
// 両方の書き方に対応:
import styles from './index.module.css'  // ✅ Vite 推奨

移行に適さないプロジェクト

  • Webpack プラグインエコシステムに強く依存しているプロジェクト(Module Federation、特殊な loader)
  • レガシーな CommonJS プロジェクト(Vite の開発環境は ESM を使用)
  • IE11 との互換性が必要なプロジェクト(Vite は対応していない)

まとめ

  • Webpack のチューニングで 45s から 6s に改善できるが、天井がある
  • Vite は開発体験を根本的に変えた:オンデマンドコンパイル + esbuild の事前ビルド
  • 新規プロジェクトは直接 Vite を、既存プロジェクトは Webpack プラグイン依存を評価して移行判断
  • プロダクションビルドの差は小さく、Vite の Rollup tree-shaking がやや優位
  • 2021 年、Vite は Vue 3 プロジェクトの事実上の標準となった

MIT Licensed