WSL2 で Vite の HMR が効かない・ファイル変更が反映されない時の原因と対策【hot reload / inotify / polling】
公開日:2026-08-24/カテゴリ:Vite・WSL2・開発環境/AnchorUp 技術ブログ
WSL2 で Vite HMR が効かない症状
WSL2 環境で npm run dev を起動してブラウザで開発中、ファイルを保存してもブラウザが自動更新されない——この問題に直面したことがある方は多いはずです。
具体的な症状:
- ブラウザのコンソールに
[vite] hmr connectedと表示されているのに反映されない - VSCode でファイルを保存してもターミナルにファイル変更のログが出ない
npm run dev直後は動くが、しばらくすると反応しなくなる- Windows 側のエディタで保存すると特に起きやすい
原因は一つ:inotify が Windows ファイルシステムの変更を検知できない
Vite はデフォルトで Linux の inotify システムコールを使ってファイルの変更を監視しています。しかし WSL2 の /mnt/c/ ディレクトリ(Windows の NTFS ファイルシステムのマウント)では、inotify がファイル変更イベントを受け取れません。
原因:WSL2 と inotify の仕組み
WSL2 はその名の通り、Windows 上で動く Linux 仮想マシンです。ファイルシステムは大きく 2 種類存在します:
| ファイルシステム | パス例 | inotify |
|---|---|---|
| WSL2 ネイティブ(ext4) | ~/projects/myapp |
✅ 動作する |
| Windows マウント(NTFS) | /mnt/c/Users/.../myapp |
❌ 検知できない |
Windows 側のエディタ(VSCode の Remote WSL 含む)がファイルを保存しても、NTFS 側の変更イベントは WSL2 の Linux カーネルには届きません。Vite の chokidar(ファイル監視ライブラリ)が使う inotify がイベントを受け取れないため、HMR が発火しません。
解決策1:プロジェクトを WSL2 ネイティブファイルシステムに移す(最善策)
これが唯一の根本解決です。 パフォーマンスも大幅に改善されます。
# NG: Windows ファイルシステム上のパス
# /mnt/c/Users/yourname/projects/myapp
# OK: WSL2 ネイティブパス
# ~/projects/myapp
# /home/yourname/projects/myapp
移行手順:
# WSL2 ターミナルで
mkdir -p ~/projects
cp -r /mnt/c/Users/yourname/projects/myapp ~/projects/myapp
cd ~/projects/myapp
npm install # node_modules を再生成
npm run dev
VSCode を使っている場合は Remote WSL 拡張機能でそのままアクセスできます:
cd ~/projects/myapp
code . # WSL2 側からプロジェクトを開く
パフォーマンスの差: NTFS マウントより ext4 ネイティブの方が
npm installで 5〜10 倍速くなるケースもあります。HMR 以外の理由でもネイティブファイルシステムへの移行を強く推奨します。
解決策2:polling モードを有効にする
どうしても Windows ファイルシステム上で作業する場合のバンドエイド的対策です。chokidar のポーリングモードを有効にすると、inotify に頼らず一定間隔でファイルの変更を確認します。
// vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
server: {
watch: {
usePolling: true,
interval: 1000, // ポーリング間隔(ミリ秒)
},
},
})
環境変数でも制御できます:
# .env.local
CHOKIDAR_USEPOLLING=true
CHOKIDAR_INTERVAL=1000
デメリット: ファイル数が多いプロジェクトでは CPU 使用率が上がります。node_modules を監視対象から外す設定を合わせて行うと軽減できます:
// vite.config.ts
export default defineConfig({
server: {
watch: {
usePolling: true,
interval: 1000,
ignored: ['**/node_modules/**', '**/.git/**'],
},
},
})
解決策3:HMR の WebSocket 接続設定を修正する
HMR 自体は動いているのにブラウザに届かない場合、WebSocket の接続設定の問題かもしれません。WSL2 の IP アドレスと Windows ブラウザ側の接続ホストが食い違うことがあります。
// vite.config.ts
export default defineConfig({
server: {
host: '0.0.0.0', // WSL2 内サーバーを Windows から到達可能にする
hmr: {
host: 'localhost', // ブラウザが接続する HMR WebSocket のホスト
},
},
})
WSL2 の IP が動的に変わる場合(再起動のたびに変わる)は、localhost を明示することで安定します。
解決策4:inotify の watch 上限を増やす
大規模プロジェクトで「too many open files」エラーが出て HMR が止まる場合、inotify のウォッチ数上限に達している可能性があります。
現在の上限を確認:
cat /proc/sys/fs/inotify/max_user_watches
# デフォルト: 8192
上限を増やす(WSL2 内で実行):
# 一時的に増やす(再起動で元に戻る)
sudo sysctl fs.inotify.max_user_watches=524288
# 永続的に増やす
echo 'fs.inotify.max_user_watches=524288' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
WSL2 の場合、/etc/wsl.conf に設定を書くことでも永続化できます:
# /etc/wsl.conf
[boot]
command = sysctl -w fs.inotify.max_user_watches=524288
Docker + WSL2 の場合の追加設定
Docker Compose を WSL2 で使っている場合、コンテナ内の Vite にも同様の問題が起きます。
# docker-compose.yml
services:
frontend:
image: node:20-alpine
volumes:
- .:/app
working_dir: /app
command: npm run dev
ports:
- "5173:5173"
environment:
- CHOKIDAR_USEPOLLING=true
- CHOKIDAR_INTERVAL=1000
Vite の設定でホストを指定することも必要です(コンテナ外からアクセスするため):
// vite.config.ts
export default defineConfig({
server: {
host: true, // '0.0.0.0' と同等
port: 5173,
watch: {
usePolling: true,
},
},
})
症状・原因・対策の一覧
| 症状 | 原因 | 対策 |
|---|---|---|
| ファイル保存しても反応しない | /mnt/c/ に保存、inotify 未動作 | WSL2 ネイティブパスに移動 |
| Connected なのに更新されない | 同上、またはポーリング未設定 | usePolling: true を設定 |
| ブラウザが WS 接続エラー | WSL2 IP アドレスの不一致 | server.hmr.host を localhost に |
| 起動直後は動くが止まる | inotify watch 上限超過 | max_user_watches を増やす |
| Docker 内でも効かない | コンテナも NTFS 経由 | CHOKIDAR_USEPOLLING=true |
まとめ
WSL2 で Vite の HMR が効かない問題は、inotify が Windows NTFS ファイルシステムのイベントを受け取れないことが根本原因です。
推奨する対処の優先順位:
- プロジェクトを WSL2 ネイティブパス(
~/projects/)に移す → 根本解決かつパフォーマンス向上 usePolling: trueを設定する → 移行できない場合のバンドエイドserver.hmr.host: 'localhost'を指定する → WebSocket 接続の安定化max_user_watchesを増やす → 大規模プロジェクトでの上限対策
特に理由がなければ解決策1一択です。WSL2 ネイティブファイルシステムへの移行は HMR の修正だけでなく、npm install や git status の速度も劇的に改善します。