14

Ever since updating from WSL 1 to WSL 2 with the Windows 10 April 2020 update (and thereafter updating Ubuntu 18 to Ubuntu 20), I have not been able to get nodemon to hot reload when there are file changes in the project's directory. When I make any changes to .js files, there's no restarting of the server or output at the terminal:

enter image description here

I start my Node.js server with nodemon like this:

NODE_ENV=development DEBUG='knex:*' nodemon --verbose --inspect ./server.js"

And in case its useful, here is my server.js:

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server started and listening on port ${PORT}`);
});

I am not even sure how to troubleshoot this further to get more useful information about what's going on.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Raj
  • 1,479
  • 3
  • 15
  • 29
  • 2
    have you tried `nodemon -L`? – Simperfy Aug 16 '20 at 11:32
  • 1
    @Simperfy, you're right, it works as expected with `nodemon -L`, thank you. Why am I needing to use the legacy watcher? – Raj Aug 18 '20 at 01:12
  • 1
    Added the "why" to my answer - It turns out that WSL2 doesn't fully support inotify on the Windows filesystem (being handled by the 9P filesystem protocol). – NotTheDr01ds Aug 18 '20 at 21:49

2 Answers2

36

Root cause:

inotify is not fully supported in the 9P filesystem protocol on WSL2.

There are several github issues on the WSL project related to this, but perhaps the most relevant is #4739.

Possible Workarounds:

  1. Try nodemon -L (a.k.a. --legacy-watch) as Simperfy suggested.

  2. Try running from the default ext4 filesystem (e.g. mkdir -p $HOME/Projects/testserver). Note that a symlink to the Windows filesystem will still not work. As a bonus, the WSL ext4 filesystem will be much faster for file intensive operations like git.

    You can still access the source from Windows editors and tools through \\wsl$\.

  3. Use Visual Studio Code with the Remote-WSL extension to edit your source on the Windows filesystem. The easiest way to do this is by navigating in WSL to your project directory and running code ..

    Visual Studio Code's WSL integration does trigger inotify for some reason.

  4. Downgrade the session to WSL1 if you don't need any of the WSL2 features. I keep both WSL1 and WSL2 sessions around. The best way to do this is to create a backup of the session with wsl --export and wsl --import. You can switch the version of a WSL distro at any point with wsl --set-version.

    I did test this on WSL1 with a sample project under the Windows filesystem, and editing via something as basic as notepad.exe under Windows still triggered nodemon to restart.

Longer answer:

nodemon worked "out of the box" for me on WSL2 on the root (/) ext4 mount (e.g. $HOME/src/testserver).

It also worked correctly when I tried it under the default /mnt/c mount that WSL/WSL2 creates. Of course, /mnt/c is much slower under WSL2. Edit - It turns out that I was using Visual Studio Code when I attempted this. Editing from other Windows apps on the Windows filesystem did not trigger nodemon to restart.

But looking at the first line of your screenshot, I see that you are running this from /c/Users/.... I'm thinking maybe you created this (perhaps CIFS) mount to try to work around the WSL2 performance issues - It's a common workaround.

I didn't set up a CIFS mount, but I was able to reproduce your problem by mounting with (substituting your Windows username):

mkdir $HOME/mnttest
sudo mount -t drvfs 'C:' $HOME/mnttest
cd $HOME/mnttest/Users/Raj/Projects/testserver

Running nodemon from this mount failed in the same manner that you describe -- Changes to the source did not trigger a restart.

However, running with nodemon -L on this mount did trigger a restart when source files were changed.

It also may be possible to fix the problem by mounting with different options, but I'm just not sure at this point. Edit - Seems unlikely, given the bug reports on this on Github.

Also, you may want to create some exports/backups of your WSL sessions. It's too late at this point (for your previous install), but you could have run wsl.exe --export to create a backup of the Ubuntu 18.04/WSL1 filesystem before upgrading. You can also change the version of a particular distribution with wsl.exe --set-version. This could give you some better "before/after" test comparisons.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70
  • 2
    Very nice explanation, thank you. Just as you thought, it works as expected with `nodemon --legacy-watch`. Can you perhaps tell me how to fix this so the legacy watcher isn't necessary? – Raj Aug 18 '20 at 01:14
  • I did `cd $HOME/Projects/testserver` and then ran `nodemon` without `-l`, but it didn't recognize file changes again. I should mention that Projects is a symlink: https://i.imgur.com/5gzX99G.png – Raj Aug 18 '20 at 01:56
  • Added a few more workarounds other than --legacy-watch. – NotTheDr01ds Aug 18 '20 at 21:44
  • Also, the symlink still means that the source is on the Windows filesystem and will have the inotify problem (as you've seen). You'll have to truly be on the WSL2 ext4 filesystem to get full inotify support. – NotTheDr01ds Aug 18 '20 at 21:47
  • 2
    Again, great answer, thank you. I do want to mention that I after navigating to `cd $HOME/Projects/testserver` (again `Projects` is a symlink), and then type `code .` which starts VSCode with `WSL:Ubuntu` in the statusbar: https://i.imgur.com/lv9WQUa.png , File changes are still not recognized (hot reload still doesn't work). – Raj Aug 19 '20 at 04:42
  • Do you happen to have both a `/C/...` and a `/mnt/c/...`? If so, can you try symlinking to the project in `/mnt/c`? – NotTheDr01ds Aug 19 '20 at 05:18
  • Also try forcing a restart of the WSL session by (save all work first, then ...) doing a `wsl --shutdown` from cmd or Powershell and then restarting the WSL2 session. – NotTheDr01ds Aug 19 '20 at 05:22
  • `/c/Users/Raj` is the default directory Windows Terminal opens to. Both `/c` and `/mnt/c` exist, but `/mnt/c` is empty and `/c` has all my WIndows files. https://i.imgur.com/VBhla9l.png . Additionally, hotreload doesn't work in VSCode even after doing a `wsl --shutdown`. Moving my projects to the Linux filesystem did resolve the issue, but it's very disappointing that inotify doesn't work if files are on the Windows filesystem. Anyway, thank you very much for your super answer. – Raj Aug 19 '20 at 07:39
  • Thanks Raj. Wish I knew what was causing mine to work under VSCode and yours not. I thought the default mountpoint for Windows drives was `/mnt/`, so the fact that yours is showing up in root (`/C`) is the only difference that I can see. I changed my `/etc/wsl.conf` to move the automount point to the root, but VSCode still works in that case. Are you using `/etc/wsl.conf`, and if so, what are your mount options? – NotTheDr01ds Aug 19 '20 at 15:37
  • And definitely agree that this is (yet another) step backwards for WSL2. I hadn't come across the problem yet myself, but given my workflow, I'd have seen it soon, so working through this was useful to the both of us. Given this problem, the performance issues of the Windows filesystem, and the lack of network bridging in WSL2; I'm probably going to continue to use WSL1 as my main environment until and unless I need Docker support or another feature that's only available in WSL2. – NotTheDr01ds Aug 19 '20 at 15:38
  • I believe I may have changed my root to be `/c` instead of `/mnt/c` because of some previous issue with Docker. My `/etc/wsl.conf` looks like this https://paste.ee/p/7ch8o – Raj Aug 21 '20 at 18:09
  • 1
    Thanks a lot! `nodemon -L index.js` works perfect. Win 10, WSL2 (Ubuntu 20) – Stanislav Hmelevsky Jan 18 '22 at 13:36
5

I am using the WSL 2 and I solved the issue by adding the following env variable: CHOKIDAR_USEPOLLING=true.

This is how looks like my nodemon command:

CHOKIDAR_USEPOLLING=true nodemon index.js

Now you can keep WSL2 instead of moving your environment to WSL1.

Areizas
  • 51
  • 1
  • 2
  • 2
    Doesn't that have exactly the same effect as `nodemon -L` or `nodemon --legacy-watch` which was mentioned in Simperfy's original comment (and my answer), just more to type? The environment variable could be used to turn it off in all sessions if added to a startup script, though. – NotTheDr01ds Feb 08 '21 at 00:47
  • Actually, it does work for me, while the legacy watch mode did not. – batjko Jun 16 '21 at 00:08