エンジニアが知っておきたい「npm run build」の全て!
エンジニアが知っておきたい「npm run build」の全て!
はじめに
今回は、普段何気なく実行しているnpm run build
について、Next.js 14での実際のビルド結果を見ながら解説します。
特に、Vercelへのデプロイ前に確認すべきポイントを重点的に説明します。
npm run buildとは?
開発環境(localhost:3000)で作成したコードを本番環境で動作させるために必要な変換処理です。
Next.js 14のプロジェクトでは、主に以下の処理を行います。
- TypeScript(v5.0以上)のコードをJavaScriptへコンパイル
- ReactコンポーネントをNext.jsのチャンクファイルへバンドル化
- 画像をWebP形式へ変換(最大80%の圧縮率)
- 静的ページの生成(SSG)とキャッシュの作成
重要な専門用語の解説
Fast Refresh
Next.jsの開発環境で使用される高速な更新機能です。
- コードを保存すると、変更された部分のみを自動で再読み込み(約0.3秒)
- Reactコンポーネントの状態(state)を保持したまま更新
- エラーが発生しても開発サーバーが停止せず、エラー画面を表示
// Fast Refreshが効く例(src/components/Button.tsx)
export const Button = () => {
const [count, setCount] = useState(0) // この値は更新時も保持される
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}
コンパイラの違い(webpack vs swc)
Next.js 14では2種類のコンパイラを選択できます:
-
webpack(デフォルト)
- 歴史が長く(2012年~)、プラグインが豊富(約8,000個)
- ビルド時間:中規模プロジェクト(100ページ)で約180秒
- メモリ使用量:約2GB
-
SWC(Speedy Web Compiler)
- Rustで書かれた新しいコンパイラ(2019年~)
- ビルド時間:中規模プロジェクトで約45秒(webpackの4倍高速)
- メモリ使用量:約800MB
設定方法:
// next.config.js
module.exports = {
// swcを有効化
swcMinify: true,
// webpackを使用する場合
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
return config
},
}
App RouterとPages Routerの違い
App Router(Next.js 13.4以降)
src/
├── app/ # App Router
│ ├── layout.tsx # 共通レイアウト
│ ├── page.tsx # トップページ(/)
│ └── about/
│ └── page.tsx # Aboutページ(/about)
ビルド時の特徴:
- サーバーコンポーネントがデフォルト(JavaScriptバンドルサイズが約40%削減)
- 静的・動的レンダリングの自動最適化
- ビルド時間:Pages Routerと比べて約20%増加
Pages Router(従来型)
src/
├── pages/ # Pages Router
│ ├── _app.tsx # 共通レイアウト
│ ├── index.tsx # トップページ(/)
│ └── about.tsx # Aboutページ(/about)
ビルド時の特徴:
- クライアントコンポーネントがデフォルト
-
getStaticProps
/getServerSideProps
による明示的なデータフェッチ - ビルド時間:App Routerと比べて約20%短い
ビルド時の挙動の違い
- App Router
# ビルドログの例
✓ Creating an optimized production build
✓ Compiled successfully
✓ Generating static pages (6/6)
├─ / # サーバーコンポーネント
├─ /about # 静的ページ
└─ /_not-found # 404ページ
✓ Collecting build traces
- Pages Router
# ビルドログの例
✓ Creating an optimized production build
✓ Compiled successfully
✓ Generating static pages (4/4)
├─ / (ISR: 60 seconds) # インクリメンタル静的再生成
├─ /about # 静的ページ
└─ 404 # 404ページ
✓ Finalizing page optimization
package.jsonでの設定例
{
"scripts": {
"dev": "next dev --port 3000",
"build": "next build",
"build:prod": "NODE_ENV=production ANALYZE=true next build",
"start": "next start --port 3001",
"lint": "next lint --dir src"
}
}
各スクリプトの使い分け
-
npm run dev
: ローカル開発時に使用。localhost:3000
で起動し、Fast Refresh対応 -
npm run build
: 検証環境(dev/stg)デプロイ時に使用。基本的な最適化を実行 -
npm run build:prod
: 本番環境デプロイ時に使用。@next/bundle-analyzer
でバンドルサイズを解析(バンドルサイズを解析するには、事前にnpm install @next/bundle-analyzer
の実行が必要です) -
npm run start
: AWS EC2やGCP Compute Engineで運用する場合に使用。3001
ポートで起動 -
npm run lint
: GitHub PRを出す前に実行。src
ディレクトリ配下のコードをチェック
一般的なビルドプロセス
実際のNext.js 14プロジェクトでは、以下の順序で処理が行われます。
-
依存関係の解決(約10-30秒)
-
node_modules
(通常2-3GB)内のパッケージを読み込み -
package-lock.json
との整合性チェック
-
-
TypeScriptのトランスパイル(約5-10秒)
// 変換前(src/components/Heading.tsx) const Heading: React.FC<{title: string}> = ({title}) => <h1>{title}</h1> // 変換後(.next/server/chunks/123.js) const Heading=({title:e})=>react_.createElement("h1",null,e)
-
コードの最小化(約10-20秒)
// 変換前(src/utils/calculate.ts) export function calculateTotalPrice(price: number, taxRate: number = 0.1) { return price + (price * taxRate); } // 変換後(.next/static/chunks/456.js) export const c=(p,t=.1)=>p+p*t
-
不要コードの削除(約3-5秒)
// 変換前(src/pages/index.tsx) import { formatDate, formatPrice, formatPhone } from '@/utils/formatters'; const price = formatPrice(1000); // formatDateとformatPhoneは未使用 // 変換後(.next/static/chunks/789.js) import{b as formatPrice}from"./formatters.js";const price=formatPrice(1e3)
-
画像の最適化(約15-30秒)
- JPG/PNGをWebPに変換(品質85%で約60-80%のサイズ削減)
- 画像を3つのサイズ(640px, 750px, 828px)に自動リサイズ
メリット・デメリット
メリット
-
本番環境用の最適化
- JavaScriptファイルを最大70%圧縮(例:1MBのコードが300kBに)
- 画像を自動的にWebP形式に変換(JPEGと比べて約30%軽量化)
- 未使用のCSSを削除(Tailwind CSSの場合、約95%削減可能)
-
配信効率の改善
- ページの初期読み込み時間が約40%短縮(Lighthouse scoreで90+を達成)
- CDN(Vercel/Cloudflare)でのキャッシュ効率が向上
- モバイル回線(4G)での読み込みが2秒以内に
-
ブラウザ互換性の確保
- 最新のTypeScript(v5.0)のコードを古いブラウザ(IE11)でも動作
- ES6+の機能(async/await等)を自動的にES5に変換
- CSS Grid/Flexboxのベンダープレフィックスを自動付与
-
コードの品質管理
- ESLintで一般的なバグを事前検出(約80%のバグを防止)
- TypeScriptの型エラーを100%検出
- consoleやdebuggerの本番環境への混入を防止
-
チーム開発の効率化
- CIでのビルドチェックで問題のあるPRを早期発見(約30分の時間節約)
- 共通の開発環境(node v18.17.0以上)を強制
- コードフォーマット(Prettier)の統一を確認
デメリット
-
ビルド時間の長さ
- 初回ビルドに3-5分かかる(node_modulesのサイズが2GB超の場合)
- Vercelの無料プランだと1回のビルドで約320秒の制限
- M1 MacBookと比べてWindowsは約1.5倍の時間が必要
-
複雑な設定要件
- next.config.jsの設定が複雑(webpack/swcの理解が必要)
- 環境変数(.env)の管理が面倒(dev/stg/prod×API_KEY等)
- サードパーティライブラリとの相性問題(特にMaterial UI v4)
-
デバッグの難しさ
- ソースマップの生成で容量が約2倍に
- 本番ビルドでのエラーがローカルで再現しづらい
- Chromeの開発者ツールでの追跡が難しい(コード難読化のため)
-
リソース消費
- メモリ使用量が4GB以上(M1 Mac 8GBだとスワップ発生)
- node_modulesのディスク容量が2-3GB必要
- CI/CDの実行時間がGitHub Actionsの無料枠(2000分/月)を圧迫
-
学習コスト
- webpack/Babelの基礎知識が必要(約1週間の学習)
- 最適化設定の理解に時間がかかる(公式ドキュメント約3時間)
- トラブルシューティングの経験が必要(Stack Overflowで解決できない問題も)
実際のビルド結果を読み解く
ビルドログの詳細解説
✓ Compiled successfully # TypeScript/JSXのコンパイル完了
✓ Linting and checking validity of types # ESLintとTypeScriptの型チェック完了
✓ Collecting page data # pages/もしくはapp/ディレクトリの解析
✓ Generating static pages (5/5) # getStaticPropsの実行とHTMLの生成
✓ Collecting build traces # 依存関係の追跡情報収集
✓ Finalizing page optimization # 画像圧縮やCSSの最適化
これらのチェックマークは、ビルドプロセスの各段階が正常に完了したことを示しています。
要注意!ビルドサイズの分析
Route (app) Size First Load JS
┌ ○ / 5.57 kB 111 kB
└ ○ /_not-found 979 B 106 kB
First Load JSが100kBを超えている場合は要注意です!
以下の対策で20-30%の削減が可能です。
-
next/image
の使用で画像を最適化(JPG/PNGから自動でWebPに変換) -
react-icons
(約1.5MB)などの大きなライブラリをdynamic import
で遅延ロード// 具体例 import dynamic from 'next/dynamic' const FaIcon = dynamic(() => import('react-icons/fa').then(mod => mod.FaIcon))
- Material UIの代わりにTailwind CSS(約40kB)を使用してバンドルサイズを削減
共有リソースの確認
+ First Load JS shared by all 105 kB
├ chunks/4bd1b696-20882bf820444624.js 52.9 kB
├ chunks/517-fe882a976a10ccc2.js 50.5 kB
└ other shared chunks (total) 1.95 kB
全ページで共有されるJavaScriptファイルの内訳です。
トラブルシューティング
よくある問題と解決方法
-
ビルドが遅い場合
- 不要なパッケージの削除
- キャッシュの活用
- ビルド設定の最適化
-
メモリ不足エラー
# Node.jsのメモリ制限を緩和 NODE_OPTIONS="--max-old-space-size=4096" npm run build
-
依存関係の問題
# node_modulesを削除して再インストール rm -rf node_modules npm install
まとめ
ビルド結果を定期的にチェックすることで、以下のような具体的な改善が可能です。
パフォーマンスの予測
- Lighthouseスコアが90点以上になるかを事前に確認
- First Load JSが100kB以下になるようコード分割
- 画像の合計サイズを1ページあたり500kB以下に抑制
最適化状態の確認
-
@next/bundle-analyzer
でチャンクサイズの肥大化をチェック - 未使用のimport文を
eslint-plugin-unused-imports
で検出 -
next/image
の使用漏れをeslint-plugin-next
でチェック
開発効率の向上
- ビルド時間を3分以内に抑えてCI/CDを効率化
- PRレビュー時にバンドルサイズの変更を必ずチェック
- Vercelのデプロイプレビューで本番の動作を確認
毎日のPRマージ前にnpm run build:prod
を実行し、上記の項目をチェックすることで、パフォーマンスの高いNext.jsアプリケーションを維持できます!
Discussion