Vite でパフォーマンスを追求するプロファイリング手法

Vite を使ったフロントエンド開発において、「なぜビルドが遅いのか?」「開発サーバーの起動に時間がかかるのはなぜか?」といった疑問を抱えたことはありませんか?
現代の Web アプリケーション開発では、パフォーマンスが直接的にユーザー体験や開発効率に影響します。Vite は高速な開発体験を提供してくれる素晴らしいツールですが、プロジェクトが成長するにつれて、適切なプロファイリング手法を身につけることが、真の意味でのパフォーマンス最適化への第一歩となるのです。
背景
Vite のビルドシステムとパフォーマンス特性
Vite は、ES ビルドと Rollup を組み合わせた革新的なビルドツールです。開発時には ES modules を活用した高速な HMR(Hot Module Replacement)を提供し、本番ビルド時には Rollup による最適化を行います。
しかし、この二段構えのアプローチゆえに、パフォーマンス問題の原因を特定するには、それぞれの段階での計測が必要になります。
typescript// vite.config.ts - 基本的な設定例
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
},
});
モダンフロントエンド開発におけるパフォーマンス要求の高まり
現在の Web アプリケーションは、ユーザーが期待する応答性が以前とは比較にならないほど高くなっています。Google の研究によると、ページの読み込み時間が 1 秒から 3 秒に増加すると、直帰率は 32%増加するとされています。
開発者にとっても、ビルド時間の短縮は生産性に直結します。1 日に何十回もビルドを実行する開発現場では、わずか数秒の改善でも大きな効果をもたらします。
プロファイリングによる可視化の必要性
「感覚的に遅い」から「具体的にどこが遅いのか」を知ることで、初めて適切な対策を講じることができます。プロファイリングは、パフォーマンス問題を推測ではなく、データに基づいて解決するための必須スキルなのです。
課題
ビルド時間の増大問題
プロジェクトの規模が大きくなるにつれて、以下のような典型的なエラーメッセージに遭遇することがあります:
bash# よく見られるビルドタイムアウトエラー
Error: Timeout of 60000ms exceeded.
at Timeout.<anonymous> (/node_modules/rollup/dist/rollup.js:25123:24)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7)
このエラーは、ビルドプロセスが期待される時間内に完了しなかったことを示しています。大規模なプロジェクトでは、数百から数千のモジュールを処理する必要があり、依存関係の解析だけでも相当な時間を要します。
開発サーバーの起動速度低下
開発サーバーの起動が遅い場合、以下のようなログが出力されることがあります:
bash# 開発サーバー起動時の警告例
vite v4.4.5 dev server running at:
> Local: http://localhost:5173/
> Network: use --host to expose
ready in 12.3s
⚠ Large number of files detected (2847).
Consider using .gitignore to exclude unnecessary files.
このような警告は、Vite が多数のファイルを監視しようとしていることを示しています。不要なファイルまで監視対象に含まれている可能性があります。
バンドルサイズの肥大化
本番ビルド後に予想以上にファイルサイズが大きくなってしまうケースも頻繁に発生します:
bash# ビルド結果の例(サイズが大きすぎる場合)
dist/assets/index-a1b2c3d4.js 2,847.23 kB │ gzip: 856.34 kB
⚠ Some chunks are larger than 500 kBs after minification.
Consider using dynamic imports or code splitting.
HMR(Hot Module Replacement)の遅延
開発時に特に問題となるのが、HMR の応答速度です。ファイルを変更してから反映されるまでの時間が長いと、開発体験が著しく悪化します:
javascript// HMR エラーの例
[vite] hmr update /src/components/LargeComponent.tsx failed:
Error: Failed to reload /src/components/LargeComponent.tsx.
This could be due to syntax errors or dependency issues.
at updateModules (vite/client:247:15)
at handleMessage (vite/client:123:7)
解決策
Vite 内蔵のプロファイリング機能の活用
Vite には強力な内蔵プロファイリング機能が搭載されています。まず基本的な--profile
オプションから始めてみましょう:
bash# 基本的なプロファイリングコマンド
yarn vite build --profile
# より詳細な情報を取得
yarn vite build --profile --logLevel info
このコマンドを実行すると、以下のような出力が得られます:
bash# プロファイリング結果の例
✓ building for production...
✓ 247 modules transformed.
Build performance:
- Plugin execution: 1.2s
- Rollup bundling: 3.4s
- Asset processing: 0.8s
- Total build time: 5.4s
Top 5 slowest plugins:
1. @vitejs/plugin-react: 456ms
2. vite:build-html: 234ms
3. vite:terser: 189ms
4. vite:css: 167ms
5. vite:asset: 143ms
プラグインパフォーマンスの計測手法
個別のプラグインのパフォーマンスを詳細に計測するには、カスタムの計測ロジックを実装することが効果的です:
typescript// プラグインパフォーマンス計測の実装
import { Plugin } from 'vite';
function createPerformancePlugin(): Plugin {
const startTimes = new Map<string, number>();
return {
name: 'performance-monitor',
configResolved() {
console.log('🚀 Performance monitoring started');
},
buildStart() {
startTimes.set('build', Date.now());
},
generateBundle() {
const buildTime =
Date.now() - startTimes.get('build')!;
console.log(`📊 Build completed in ${buildTime}ms`);
},
};
}
依存関係分析とボトルネック特定
依存関係の分析には、専用のプラグインを活用します:
bash# Bundle Analyzerのインストール
yarn add --dev rollup-plugin-visualizer
# プラグインの設定後、分析実行
yarn vite build --mode production
設定ファイルでの実装例:
typescript// vite.config.ts - Bundle Analyzer設定
import { defineConfig } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
// 他のプラグイン...
visualizer({
filename: 'dist/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}),
],
});
メモリ使用量の監視方法
Node.js のメモリ使用量を監視するスクリプトを作成しましょう:
javascript// scripts/memory-monitor.js
function formatBytes(bytes) {
return (
Math.round((bytes / 1024 / 1024) * 100) / 100 + ' MB'
);
}
function logMemoryUsage() {
const usage = process.memoryUsage();
console.log(`🧠 Memory Usage:`);
console.log(` RSS: ${formatBytes(usage.rss)}`);
console.log(
` Heap Used: ${formatBytes(usage.heapUsed)}`
);
console.log(
` Heap Total: ${formatBytes(usage.heapTotal)}`
);
console.log(
` External: ${formatBytes(usage.external)}`
);
}
// 定期的にメモリ使用量をログ出力
setInterval(logMemoryUsage, 5000);
具体例
vite --profile
コマンドの実践的活用
実際のプロジェクトでプロファイリングを実行してみましょう。以下は、典型的な大規模 React プロジェクトでの事例です:
bash# 詳細プロファイリングの実行
yarn vite build --profile --mode production
# 出力例
vite v4.4.5 building for production...
✓ 1,247 modules transformed.
✓ built in 23.45s
Performance breakdown:
┌─────────────────────────┬────────────┬─────────┐
│ Phase │ Time (ms) │ Percent │
├─────────────────────────┼────────────┼─────────┤
│ Plugin Resolution │ 2,340 │ 9.9% │
│ Module Transformation │ 12,890 │ 55.0% │
│ Rollup Bundling │ 6,780 │ 28.9% │
│ Asset Optimization │ 1,440 │ 6.1% │
└─────────────────────────┴────────────┴─────────┘
この結果から、モジュール変換の段階で最も時間がかかっていることがわかります。
Bundle Analyzer を使った詳細分析
Bundle Analyzer の実行結果から問題を特定する例:
typescript// 問題のあるimportの例
import * as _ from 'lodash'; // 😰 全体をimport(約70KB)
// 改善されたimport
import { debounce, throttle } from 'lodash-es'; // 😊 必要な関数のみ
Analyzer の結果から、lodash 全体が含まれていることが判明した場合の対処法:
typescript// vite.config.ts - Tree Shakingの改善
export default defineConfig({
build: {
rollupOptions: {
external: ['lodash'],
output: {
globals: {
lodash: '_',
},
},
},
},
optimizeDeps: {
include: ['lodash-es'],
},
});
Node.js Profiler との連携テクニック
より詳細なプロファイリングには、Node.js の内蔵プロファイラーを活用します:
bash# Node.js プロファイラーでViteを実行
node --prof node_modules/.bin/vite build
# プロファイル結果の解析
node --prof-process isolate-*.log > vite-profile.txt
プロファイル結果の読み方:
bash# プロファイル結果の例(抜粋)
[Summary]:
ticks total nonlib name
892 17.8% 17.8% JavaScript
3,456 69.1% 69.1% C++
234 4.7% 4.7% GC
89 1.8% Shared libraries
329 6.6% Unaccounted
[JavaScript]:
ticks total nonlib name
234 4.7% 4.7% LazyCompile: transform /node_modules/esbuild/lib/main.js:1234:15
189 3.8% 3.8% LazyCompile: parse /node_modules/rollup/dist/rollup.js:5678:20
カスタムプロファイリングスクリプトの実装
開発チーム独自のプロファイリングスクリプトを作成することで、継続的な監視が可能になります:
javascript// scripts/build-profiler.js
import { performance } from 'perf_hooks';
import { exec } from 'child_process';
import fs from 'fs';
class BuildProfiler {
constructor() {
this.metrics = {};
this.startTime = 0;
}
start() {
this.startTime = performance.now();
console.log('🎯 Build profiling started...');
}
markPhase(phaseName) {
const currentTime = performance.now();
this.metrics[phaseName] = currentTime - this.startTime;
console.log(
`✅ ${phaseName}: ${this.metrics[phaseName].toFixed(
2
)}ms`
);
}
async runBuild() {
this.start();
return new Promise((resolve, reject) => {
exec('yarn vite build', (error, stdout, stderr) => {
this.markPhase('Complete Build');
if (error) {
console.error('❌ Build failed:', error);
reject(error);
return;
}
this.saveReport();
resolve(stdout);
});
});
}
saveReport() {
const report = {
timestamp: new Date().toISOString(),
metrics: this.metrics,
totalTime: this.metrics['Complete Build'],
};
fs.writeFileSync(
`build-reports/report-${Date.now()}.json`,
JSON.stringify(report, null, 2)
);
console.log('📊 Performance report saved');
}
}
// 使用例
const profiler = new BuildProfiler();
profiler.runBuild().catch(console.error);
継続的なパフォーマンス監視のための設定:
json// package.json - カスタムスクリプト
{
"scripts": {
"build:profile": "node scripts/build-profiler.js",
"build:analyze": "yarn build && yarn analyze",
"analyze": "npx serve dist/stats.html"
}
}
まとめ
Vite でのパフォーマンスプロファイリングは、単なる技術的な作業以上の価値があります。それは、あなたの開発体験を根本的に向上させ、ユーザーにより良いプロダクトを届けるための投資なのです。
今回ご紹介した手法を実践することで、以下のような成果を期待できます:
- ビルド時間の 30-50%短縮:適切なプロファイリングにより、ボトルネックを特定し、的確な最適化が可能
- 開発効率の大幅向上:HMR の高速化により、コード変更からプレビューまでの時間を短縮
- バンドルサイズの最適化:不要な依存関係を除去し、ユーザー体験の向上を実現
パフォーマンスプロファイリングは継続的なプロセスです。一度設定すれば終わりではなく、プロジェクトの成長とともに定期的に見直し、改善を続けることが重要です。
あなたの次のプロジェクトでも、ぜひこれらの手法を活用して、より快適で効率的な開発体験を実現してください。きっと、コードを書くことがもっと楽しくなるはずです。
関連リンク
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来