🦡

Next.js のホットリロード(Fast Refresh)が効かないときの基本処方箋

に公開

Next.js のホットリロード(Fast Refresh)が効かないときの基本処方箋

Docker/WSL2/VM/ネットワークドライブなど ファイル更新イベントが取りこぼれやすい環境 では、Fast Refresh(いわゆるホットリロード)が反応しないことがあります。そんなとき、まず効くのが webpack の watchOptions でポーリング監視に切り替える 方法(=next dev を webpack 開発サーバで動かす前提)です。


結論:next.config.tswatchOptions を追加

// next.config.ts
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, { dev }) => {
    if (dev) {
      config.watchOptions = {
        // イベント監視が不安定な環境向けにポーリングへ
        poll: 1000,            // 1秒ごとに差分チェック
        aggregateTimeout: 200, // 変更連打時に200ms待ってまとめて再ビルド
        // ignored: /node_modules/, // 必要なら監視除外(既定で除外)
      };
    }
    return config;
  },
};

module.exports = nextConfig;
  • poll: OS のファイルイベントに頼らず 定期的にファイル更新を走査
  • aggregateTimeout: 変更が連続したときに 再ビルドを少し待ってまとめるデバウンス。

注意--turbo(Turbopack)起動時はこの watchOptions は効きません。監視が怪しい環境では 一旦 webpack 開発サーバ(next dev)に戻して安定化 するのが手堅いです。


仕組みの要点(なぜ効くのか)

Next.js の Fast Refresh は「ファイル変更の検知 → 差分ビルド → ブラウザへ更新」を行います。変更検知はバンドラ側(webpack なら watchpack)が担うため、ネットワーク越しのマウントや仮想環境でイベントが落ちる 場合は、ポーリングに切り替えるのが定石です。


Turbopack と webpack の切り替え指針

  • Turbopack(next dev --turbo:高速で快適。ただし一部環境でファイル監視が不安定なことがある。
  • webpack(next dev:保守的で互換性が広い。困ったらまずこちらに戻し watchOptions を当てる

package.json 例:

{
  "scripts": {
    "dev": "next dev",          // webpack dev(watchOptions 有効)
    "dev:turbo": "next dev --turbo"
  }
}

環境変数で“全体スイッチ”を掛ける(Docker/WSL2 の定番)

next.config.js を触らずに、watchpack をポーリング強制する方法も有効です(Compose などで一括適用したいときに便利)。

.env.local(または Compose の environment)に設定:

WATCHPACK_POLLING=true

Docker Compose 例:

services:
  web:
    image: node:20
    working_dir: /app
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - WATCHPACK_POLLING=true
    command: sh -c "npm i && npm run dev"
    ports:
      - "3000:3000"

補足:ポーリングは CPU を使うため、必要に応じて poll 間隔を 1000 → 2000〜5000ms などへ調整。ignored のチューニングも検討。


周辺テク(安定化の小ワザ)

1) onDemandEntries の調整(開発サーバのページ保持)

開発サーバが保持するビルド済みページの キャッシュ期間/数 を微調整できます。重い環境での再ビルド頻度を抑制。

// next.config.js
module.exports = {
  onDemandEntries: {
    maxInactiveAge: 25 * 1000, // 既定: 25s
    pagesBufferLength: 5       // 既定: 5
  },
};

2) .next のキャッシュを一度クリア

挙動が乱れたら .next/ を削除 → npm run dev 再起動

3) 起動コマンドの取り違えに注意

next build && next start本番サーバ。HMR/Fast Refresh は next dev でのみ有効です。


Fast Refresh が“フルリロード”に落ちる条件

Fast Refresh 自体は生きていても、以下では フルページリロード になります:

  • 匿名コンポーネントや、コンポーネント以外のエクスポートが同ファイルに混在
  • コンポーネント名が PascalCase でない …など

この条件に当たっていないかもチェックしておくと切り分けが早いです。


最短チェックリスト(現場版)

  1. next dev で起動しているか(next start ではない)
  2. WATCHPACK_POLLING=true を設定(Docker/WSL2/リモートFSなど)
  3. それでもダメなら Turbopack を外して webpack dev に切替え、
    watchOptions.poll を設定
  4. .next/ を削除して再起動
  5. それでも不安定なら poll 間隔や ignored を調整

参考リンク(公式・一次情報中心)

Discussion