These last days I've developed a module to scrap some data with Nightmare, a headless browser based on Electron. Once my code was finished I tried to run it on Heroku's infrastructure and was pretty disappointed to see it wasn't running though it worked perfectly on my local machine.
After a bit of research, I've found that “Electron requires a display driver to function”. Of course, Heroku doesn't provide any display driver since there is nearly no incentive to that. Thankfully, the Electron team addressed this issue (on the same documentation page) and recommends to use Xvfb, a tool which allows to run a virtual display server on your machine.
heroku buildpacks:add -i 1 https://github.com/heroku/heroku-buildpack-apt
Then add a file named
Aptfile in the root directory of your app with the following contents, each line contains the name of a package we want to install:
The next time you will deploy your application, Xvfb will be installed on your dynos, however the command will not work right out of the box because of the architecture of Heroku's servers. You will need to install the Xvfb buildpack written by yoz, which patches the Xvfb command so it can run properly. Obviously, this buildpack should run after the APT one:
heroku buildpacks:add -i 2 https://github.com/captain401/heroku-buildpack-xvfb
Running the virtual display server
Now you need to run Xvfb before launching your Electron process. Instead of starting a new instance of Xvfb each time you want to run Electron, you could launch Xvfb at startup. Heroku provides the ability to run a bash script on startup through a
.profile file located at the root directory of your app. Here is what it should contain:
export DISPLAY=':99.0' Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
These two lines are copied from the configuration the Electron team provides for Travis CI. The
$DISPLAY variable identifies your Xvfb instance and will be read by Electron, according to the documentation:
Chromium in Electron will automatically look for
$DISPLAY, so no further configuration of your app is required.
In the second line we run the Xvfb server in background and define the screen properties.
One last thing, maybe you want to run the virtual display server only on one type of dyno. Heroku provides a
$DYNO variable containing the process type and an identifier. So if you want to run Xvfb only for the
scraper process type, you will need to write the following code in your
if [ -z "$DYNO" ] || [[ $DYNO == *"scraper"* ]]; then export DISPLAY=':99.0' Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & fi
[ -z "$DYNO"] part checks if the variable is unset or empty. I prefer to add this since Heroku states in its documentation:
$DYNOvariable is experimental and subject to change or removal.
Thus, if the
$DYNO variable gets removed, your virtual display server will still be running, but on all your dynos instead on the type you defined.
It might be simpler in the future
Since December, Chromium supports the
--headless command line flag which allows to run it without any display server. I don't know if Electron will integrate this feature in the future, but this could be great for saving time for developers.