How to fix Webpack’s watch feature in VirtualBox?

No Comments

Webpack’s watch feature is broken under VirtualBox. The reason is that the inotify events are not supported between shared folders. But I found a solution, to forward the events from the host system.

Motivation

During my career I had to work on lots of different projects. What I know for sure is that there are not two different projects which require the exact same set of tools.

For example my current project needs gcloud, anslibe, terraform, kubectl, docker and many other tools. Although without these programs I could not contribute to my project at all, I am pretty sure that my next project will require another set of tools.

I think if we install lots of different programs on the host system, after a certain time it will be hard to maintain them and the updates and new versions will leave left overs and after some time it will be out of control.

So that’s why I have developed a workflow to use these tools from a virtual machine (which is also nice to play around and try things out). At this point Webpack and VirtualBox enter the stage. My previous project needed npm/yarn and of course Webpack for some frontend development. These are a bunch of messy tools so I’ve decided to spin up my VM and use my nicely developed workflow to install these programs.

The project source was in a shared folder so I could edit it from the host system in IntelliJ and start the development server on the guest OS.

Problem

I found out pretty quickly that the Webpack’s watch feature is not working at all, and that’s why the code won’t be automatically recompiled and the hot reloaded function won’t work either after editing. So I had to go to the browser every time and manually refresh the page and wait for compiling and reloading. It felt like my development workflow was 30% slower, because of this one manual step. After a certain time I was so frustrated that I have to refresh every time when I want to propagate the new changes, I decided to find out what is going on…

The issue is that VirtualBox decided not to implement the feature of inotify event forwarding in its software. You could ask what is inotify at all and why should VirtualBox implement this feature. Well.. you actually already know the answer to the why.

This is what the main page says about inotify:

The inotify API provides a mechanism for monitoring filesystem events. Inotify can be used to monitor individual files, or to monitor directories. When a directory is monitored, inotify will return events for the directory itself, and for files inside the directory.

So this program sends the trigger to Wepback and based on this trigger Webpack’s watch recompiles and reloads the page. At least this is the case for Linux systems. OSX uses fsevents for the same purpose.

Anyways the change happens on the host system from IntelliJ and the inotify should be triggered on the host system.

Solution

There are two different solutions to this problem.

The first one could be that you turn on the Webpack’s poll feature. I won’t cover this solution in this article. To be honest I am not a huge fun of this fix. If you set the polling rate to low, it can cause massive CPU usage and if you set it to high the changes will happen too slow.

The second one is what I am going to introduce you in more detail: There is a small client <-> server program called notify-forwarder which forwards the notifications from the host system to the guest system and triggers the inotify event.
In my opinion this is a more elegant and general solution to the host OS <-> guest OS notification problem and of course it will solve the gulp’s watchify issue as well, which is actually the same problem.

Setup

As a precondition I assume that you have already shared your workspace between the host and the guest OS, and it’s properly mounted.
HINT: One way to properly mount your workspace on the guest OS is to write something like this into your /etc/fstab:
workspaces /home/janos/workspaces vboxsf uid=1000,gid=1000,rw,dmode=700,fmode=600,comment=systemd.automount 0 0

First you have to setup the Port Forwarding in VirtualBox. Open VirtualBox, select your guest OS, and open settings. Under settings there is a tab called Network, select this tab and set the Adapter 1 to NAT mode. Below these settings there is an Advanced menu point, where you can setup Port Forwarding rules (see on the screenshot below).

Port Forwarding

This is pretty straight forward. The Name can be anything, the Protocol has to be UDP (watch out the default one is TCP), the Host IP is the IP address of your host system (use the loopback interface here) and the Guest IP is the IP of your guest. Since notify-forwarder uses 29324 as the default port (you can change it via parameters) you have to set it as Host Port and Guest Port.
HINT: A restart of the guest system is not necessary but to make sure that all changes are applied, just restart it!

Now you have to clone the source of notify-forwarder from this repository: https://github.com/mhallin/notify-forwarder on both systems.

Let’s compile it for both systems.

Common commands for the host and the guest systems:
git clone https://github.com/mhallin/notify-forwarder.git
cd notify-forwarder
make

Commands for the host system (after compiling with make):
cd _build
./notify-forwarder watch /your/local/workspace/ /your/mounted/workspace/on/the/guest

Commands for the guest system (after compiling with make):
cd _build
./notify-forwarder receive

If you did everything correctly, you will be able to edit your files (JS, CSS, etc..) from IntelliJ and trigger the changes automatically.

Bonus

As a bonus I will show you some automatization commands from my .zshrc (this is the equivalent of the .bashrc in the Z shell).

This is how I start my VM from the terminal:
alias startjbox="/Users/janos/Documents/workspaces/notify-forwarder/_build/notify-forwarder watch /Users/janos/Documents/workspaces /home/janos/workspaces & VBoxManage startvm arch --type headless"

As you can see I am also starting the notify-forwarder in watch modus at the same time. And of course I have the equivalent version with receiver on the guest side.
alias receiveChanges="/home/janos/workspaces_arch/notify-forwarder/_build/notify-forwarder receive"

Finally this is how I start my development server on the guest OS:
receiveChanges & yarn start

In this way I don’t even have to think about the whole process every time I start my VM. It will just always work out of the box.

As a second bonus I recommend another repository from the same guy who wrote the notify-forwarder. This repo is about another small program called vagrant-notify-forwarder, which is basically an extension of the notify-forwarder, just packed as a vagrant plugin.
It can be also useful.

Comment

Your email address will not be published. Required fields are marked *