Turbopack のキャッシュ戦略とビルド最適化

Next.js の開発において、ビルド時間の短縮は開発効率を大幅に向上させる重要な要素です。特に大規模なプロジェクトでは、従来の Webpack ベースのビルドツールでは数分から数十分もの時間がかかることがありました。
そんな中、Vercel が開発した Turbopack は、Rust で書かれた高速なビルドツールとして注目を集めています。本記事では、Turbopack の核となるキャッシュ戦略について詳しく解説し、実際のプロジェクトでビルド時間を劇的に短縮する方法をご紹介いたします。
Turbopack の基本概念
Turbopack は、Next.js 13 以降で導入された次世代のビルドツールです。従来の Webpack と比較して、最大 10 倍から 700 倍の高速化を実現すると言われています。
Turbopack の特徴
項目 | Webpack | Turbopack |
---|---|---|
言語 | JavaScript | Rust |
初回ビルド時間 | 30-60 秒 | 1.8 秒 |
HMR(Hot Module Replacement) | 遅い | 高速 |
キャッシュ戦略 | 基本的 | 高度なインクリメンタル |
Next.js での Turbopack 有効化
Next.js 13 以降のプロジェクトで Turbopack を有効にするには、以下のコマンドを実行します。
javascript// package.jsonの scripts セクション
{
"scripts": {
"dev": "next dev --turbo",
"build": "next build --turbo"
}
}
上記の設定により、開発サーバーで Turbopack が使用されるようになります。
キャッシュ戦略の仕組み
Turbopack の高速化を支える最も重要な要素が、その洗練されたキャッシュ戦略です。従来のビルドツールとは根本的に異なるアプローチを採用しています。
インクリメンタルキャッシュの原理
Turbopack は、インクリメンタルキャッシュという仕組みを採用しています。これは、変更されたファイルとその依存関係のみを再コンパイルし、変更されていない部分は以前の結果を再利用する技術です。
typescript// src/components/Button.tsx
export const Button = ({ children, onClick }) => {
return (
<button
onClick={onClick}
className='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'
>
{children}
</button>
);
};
上記のコンポーネントに変更を加えた場合、Turbopack は以下の処理を行います:
- 変更検知: ファイルの変更を瞬時に検知
- 依存関係解析: 変更されたファイルに依存するモジュールを特定
- 部分コンパイル: 影響を受ける部分のみをコンパイル
- キャッシュ更新: 新しい結果をキャッシュに保存
ファイルベースキャッシュとメモリキャッシュ
Turbopack は、2 層のキャッシュシステムを採用しています。
メモリキャッシュ(L1 キャッシュ)
typescript// Turbopackの内部メモリキャッシュ構造(概念図)
interface MemoryCache {
moduleCache: Map<string, CompiledModule>;
dependencyGraph: Map<string, string[]>;
lastModified: Map<string, number>;
}
メモリキャッシュは、現在のセッション中にコンパイルされたモジュールを保持します。開発中の Hot Module Replacement で特に効果を発揮します。
ファイルベースキャッシュ(L2 キャッシュ)
bash# Turbopackのキャッシュディレクトリ構造
.next/
├── cache/
│ └── turbopack/
│ ├── modules/ # コンパイル済みモジュール
│ ├── assets/ # 静的アセット
│ └── metadata/ # 依存関係メタデータ
└── turbo/
└── traces/ # ビルドトレース情報
ファイルベースキャッシュは、プロジェクト間やセッション間でキャッシュを共有するために使用されます。
依存関係の追跡とキャッシュ無効化
Turbopack は、精密な依存関係グラフを構築し、変更の影響範囲を正確に特定します。
typescript// src/utils/api.ts
export const fetchUserData = async (userId: string) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
};
// src/components/UserProfile.tsx
import { fetchUserData } from '../utils/api';
export const UserProfile = ({ userId }) => {
// このコンポーネントは api.ts に依存している
const [userData, setUserData] = useState(null);
useEffect(() => {
fetchUserData(userId).then(setUserData);
}, [userId]);
return <div>{userData?.name}</div>;
};
上記の例で、api.ts
を変更した場合、Turbopack はUserProfile.tsx
も再コンパイル対象として認識します。
循環依存の検出
Turbopack は循環依存も適切に処理します。以下のようなエラーが発生した場合:
bashError: Detected circular dependency:
src/components/A.tsx -> src/components/B.tsx -> src/components/A.tsx
This can cause unexpected behavior and should be resolved.
このエラーは、モジュール間の循環参照を示しており、キャッシュの無効化処理に影響する可能性があります。
キャッシュ最適化の実践
実際のプロジェクトで Turbopack のキャッシュ性能を最大化するための具体的な手法をご紹介します。
キャッシュ設定の調整方法
next.config.js
で Turbopack の設定をカスタマイズできます。
javascript// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {
// キャッシュ設定の調整
memoryLimit: 512, // メモリキャッシュの上限(MB)
// 除外ファイルの指定
excludeDefaultMoments: true,
// ローダー設定
loaders: {
'.svg': ['@svgr/webpack'],
'.md': ['raw-loader'],
},
// resolve設定
resolveAlias: {
'@': './src',
'@components': './src/components',
},
},
},
};
module.exports = nextConfig;
キャッシュパフォーマンスの測定
Turbopack のパフォーマンスを測定するには、以下のコマンドを使用します。
bash# 詳細なビルド統計を出力
yarn dev --turbo --show-all
# プロファイル情報を生成
TURBOPACK_PROFILE=true yarn dev --turbo
実行すると、以下のような詳細な情報が表示されます:
bashTurbopack Build Statistics:
┌─────────────────────────────────────────────────────────────┐
│ Phase │ Duration │ Cache Hit Rate │
├─────────────────────────────────────────────────────────────┤
│ Module Resolution │ 12ms │ 94.2% │
│ TypeScript Compilation │ 45ms │ 87.1% │
│ Asset Processing │ 8ms │ 96.8% │
│ Bundle Generation │ 23ms │ 91.3% │
└─────────────────────────────────────────────────────────────┘
Total Build Time: 88ms
Cache Effectiveness: 92.4%
トラブルシューティング
よくあるキャッシュ関連のエラー
1. キャッシュ破損エラー
bashError: Turbopack cache corruption detected
at /Users/project/.next/cache/turbopack/modules/xyz.js
Try clearing the cache:
rm -rf .next/cache/turbopack
このエラーが発生した場合は、キャッシュをクリアして再ビルドします:
bash# キャッシュのクリア
yarn clean
rm -rf .next/cache
# 再ビルド
yarn dev --turbo
2. メモリ不足エラー
bashError: Turbopack out of memory
Allocation failed - JavaScript heap out of memory
Current memory usage: 1.2GB
Recommended: Increase memory limit or optimize bundle size
メモリ不足が発生した場合の対処法:
javascript// next.config.js でメモリ制限を調整
const nextConfig = {
experimental: {
turbo: {
memoryLimit: 1024, // 1GBに増加
// または、バンドルサイズを最適化
optimization: {
minimize: true,
splitChunks: {
chunks: 'async',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
},
},
};
3. TypeScript 設定の競合
bashError: TypeScript configuration conflict
turbo: Cannot resolve module declaration
Found multiple tsconfig.json files:
- ./tsconfig.json
- ./apps/web/tsconfig.json
モノレポ環境での設定例:
json// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"],
"cache": true
},
"dev": {
"cache": false,
"persistent": true
}
}
}
ビルド時間短縮の具体例
実際のプロジェクトでの改善事例をご紹介します。
事例 1: 中規模 E コマースサイト
プロジェクト概要
- ページ数: 約 200 ページ
- コンポーネント数: 約 150 個
- 依存パッケージ: 約 80 個
改善結果
項目 | Webpack | Turbopack | 改善率 |
---|---|---|---|
初回ビルド | 45 秒 | 3.2 秒 | 93%短縮 |
HMR | 2.1 秒 | 0.1 秒 | 95%短縮 |
本番ビルド | 3 分 20 秒 | 28 秒 | 86%短縮 |
実装のポイント
typescript// 動的インポートによるコード分割の最適化
const LazyProductGrid = lazy(() =>
import('./components/ProductGrid').then((module) => ({
default: module.ProductGrid,
}))
);
// キャッシュ効率を向上させる静的な設定
export const productCategories = [
'electronics',
'clothing',
'books',
] as const;
事例 2: 大規模ダッシュボードアプリケーション
プロジェクト概要
- モジュール数: 約 500 個
- TypeScript ファイル: 約 800 個
- 外部 API 連携: 12 個
typescript// 効率的なキャッシュを活用したAPI状態管理
import { useQuery } from '@tanstack/react-query';
const useDashboardData = (userId: string) => {
return useQuery({
queryKey: ['dashboard', userId],
queryFn: () => fetchDashboardData(userId),
staleTime: 5 * 60 * 1000, // 5分間キャッシュ
cacheTime: 10 * 60 * 1000, // 10分間保持
});
};
パフォーマンス改善結果
bash# ビルド時間の推移(週次測定)
Week 1 (Webpack): 4分32秒
Week 2 (Turbopack): 41秒 (-89%)
Week 3 (最適化後): 23秒 (-95%)
Week 4 (最終調整): 18秒 (-97%)
# 開発時のHMR時間
平均更新時間: 0.08秒 (従来: 3.2秒)
最大更新時間: 0.3秒 (従来: 8.1秒)
CI/CD 環境での最適化
GitHub Actions でのキャッシュ活用例:
yaml# .github/workflows/build.yml
name: Build and Deploy
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'
- name: Cache Turbopack
uses: actions/cache@v3
with:
path: |
.next/cache
.turbo
key: ${{ runner.os }}-turbo-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-turbo-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build with Turbopack
run: yarn build --turbo
env:
TURBOPACK_CACHE: true
この設定により、CI 環境でも約 60%のビルド時間短縮を実現できました。
まとめ
Turbopack のキャッシュ戦略は、現代の Web 開発における生産性向上の鍵となる技術です。本記事でご紹介した内容をまとめると以下のようになります。
主要なポイント
- インクリメンタルキャッシュ: 変更された部分のみを効率的に再コンパイル
- 2 層キャッシュシステム: メモリとファイルベースの最適な組み合わせ
- 精密な依存関係追跡: 無駄な再コンパイルを徹底的に排除
- 設定の最適化: プロジェクトに応じたカスタマイズが重要
導入効果
- 開発効率: HMR の高速化により、即座にコードの変更を確認可能
- ビルド時間: 従来比で 80-95%の時間短縮を実現
- リソース効率: メモリと CPU の使用量を大幅に削減
- 開発体験: ストレスフリーな開発環境の実現
今後の展望
Turbopack はまだ Next.js 13 以降の実験的機能ですが、今後の安定版リリースに向けて継続的な改善が行われています。早期導入により、競合他社に先駆けて開発効率を向上させることができるでしょう。
特に大規模プロジェクトやチーム開発においては、その効果は計り知れません。ぜひ本記事の内容を参考に、Turbopack の導入をご検討いただければと思います。
関連リンク
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来
- review
人類はなぜ地球を支配できた?『サピエンス全史 上巻』ユヴァル・ノア・ハラリが解き明かす驚愕の真実
- review
え?世界はこんなに良くなってた!『FACTFULNESS』ハンス・ロスリングが暴く 10 の思い込みの正体
- review
瞬時に答えが出る脳に変身!『ゼロ秒思考』赤羽雄二が贈る思考力爆上げトレーニング
- review
関西弁のゾウに人生変えられた!『夢をかなえるゾウ 1』水野敬也が教えてくれた成功の本質