Documentation Next.js

はじめに

Next.jsのFast Refresh(ホットリロード)は、開発効率を大幅に向上させる機能です。しかし、環境や設定によっては正常に動作しないことがあります。本記事では、よくある問題と解決策を解説します。

基本的な確認事項

開発サーバーの確認

# 正しいコマンドで起動しているか確認
npm run dev
# または
pnpm dev
# または
yarn dev

キャッシュのクリア

# .nextディレクトリを削除して再起動
rm -rf .next
npm run dev

# node_modulesも含めてクリーンアップ
rm -rf .next node_modules
npm install
npm run dev

package.jsonの確認

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

Server/Client Componentの問題

’use client’の位置

// ❌ 間違い:useStateを使っているのにServer Component
import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

// ✅ 正しい:'use client'を追加
'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

イベントハンドラの問題

// ❌ Server ComponentでonClickを使用
export default function Button() {
  return <button onClick={() => console.log('clicked')}>Click</button>;
}

// ✅ Client Componentに分離
// components/ClickButton.tsx
'use client';

export function ClickButton() {
  return <button onClick={() => console.log('clicked')}>Click</button>;
}

// app/page.tsx(Server Component)
import { ClickButton } from '@/components/ClickButton';

export default function Page() {
  return <ClickButton />;
}

ファイル構造の問題

無限ループの防止

// ❌ レンダリングごとにstateを更新(無限ループ)
'use client';

import { useState, useEffect } from 'react';

export default function Problem() {
  const [data, setData] = useState([]);

  // これは無限ループを引き起こす可能性がある
  setData(fetchData());

  return <div>{data.length}</div>;
}

// ✅ useEffectで適切に処理
'use client';

import { useState, useEffect } from 'react';

export default function Fixed() {
  const [data, setData] = useState([]);

  useEffect(() => {
    async function load() {
      const result = await fetchData();
      setData(result);
    }
    load();
  }, []);

  return <div>{data.length}</div>;
}

WSL2環境での問題

プロジェクトの配置場所

# ❌ Windowsドライブマウント(遅い、ファイル監視の問題)
/mnt/c/Users/username/projects/my-app

# ✅ WSL2のLinuxファイルシステム(推奨)
/home/username/projects/my-app
# または
~/projects/my-app

プロジェクトの移動

# WSL2内に移動
mkdir -p ~/projects
cp -r /mnt/c/Users/username/projects/my-app ~/projects/
cd ~/projects/my-app

# 依存関係を再インストール
rm -rf node_modules .next
npm install
npm run dev

ファイル監視の設定

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  // WSL2でファイル変更が検出されない場合
  webpack: (config, { dev }) => {
    if (dev) {
      config.watchOptions = {
        poll: 1000,        // ポーリング間隔(ms)
        aggregateTimeout: 300,
      };
    }
    return config;
  },
};

module.exports = nextConfig;

Docker環境での問題

docker-compose.yml設定

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    volumes:
      - .:/app
      - /app/node_modules  # node_modulesをホストと分離
      - /app/.next         # .nextもホストと分離
    ports:
      - "3000:3000"
    environment:
      - WATCHPACK_POLLING=true
      - CHOKIDAR_USEPOLLING=true
    command: npm run dev

Dockerfile

# Dockerfile
FROM node:20-alpine

WORKDIR /app

# 依存関係のインストール
COPY package*.json ./
RUN npm install

# ソースコードのコピー
COPY . .

# 開発サーバー起動
CMD ["npm", "run", "dev"]

next.config.js(Docker用)

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { dev }) => {
    if (dev) {
      config.watchOptions = {
        poll: 1000,
        aggregateTimeout: 300,
      };
    }
    return config;
  },
  // Docker環境でのホスト設定
  output: 'standalone',
};

module.exports = nextConfig;

Turbopack関連の問題

Turbopackを無効化

{
  "scripts": {
    "dev": "next dev",
    "dev:turbo": "next dev --turbo"
  }
}

既知の問題を確認

# Turbopackでエラーが出る場合はWebpackに戻す
npm run dev

# 問題なければTurbopackを使用
npm run dev -- --turbo

大きなファイル/node_modulesの問題

ファイル監視の除外

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { dev }) => {
    if (dev) {
      config.watchOptions = {
        ignored: [
          '**/node_modules/**',
          '**/.git/**',
          '**/.next/**',
          '**/public/**',
        ],
      };
    }
    return config;
  },
};

module.exports = nextConfig;

inotify制限の増加(Linux/WSL2)

# 現在の制限を確認
cat /proc/sys/fs/inotify/max_user_watches

# 一時的に増加
sudo sysctl fs.inotify.max_user_watches=524288

# 永続化(/etc/sysctl.confに追加)
echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

エラーログの確認

ブラウザコンソール

// 開発者ツールのコンソールで確認
// Fast Refresh関連のエラーメッセージを探す

ターミナル出力

# 開発サーバーのログを確認
npm run dev 2>&1 | tee dev.log

# 特定のエラーを検索
npm run dev 2>&1 | grep -i "error\|fail\|refresh"

デバッグモード

Next.js詳細ログ

# 詳細なログを有効化
DEBUG=* npm run dev

# Next.js固有のログ
DEBUG=next:* npm run dev

環境変数でデバッグ

# .env.local
NEXT_PRIVATE_DEBUG_CACHE=1

チェックリスト

確認項目コマンド/確認方法
キャッシュクリアrm -rf .next
依存関係の再インストールrm -rf node_modules && npm install
’use client’の確認フック使用コンポーネントに追加
WSL2ファイルシステム~/projects/に配置
Docker volumesnode_modules分離
ポーリング有効化next.config.jsで設定

まとめ

環境主な対策
一般キャッシュクリア、‘use client’確認
WSL2Linuxファイルシステムに配置
Dockerポーリング有効化、volumes設定
大規模プロジェクトinotify制限増加、除外パターン設定

参考文献

円