The days of the Microsoft Windows operating system domination are over. Apple and, to a lesser extent, Linux have taken back a major portion of the marketplace. But this presents companies with a new challenge: how to create feature-rich apps for multiple operating systems without maintaining multiple codesets.
We will use the Electron project "Simple Performance Measurement with Node.js, Electron, OpenFin and Web" to demonstrate this.
This application measures latency between a node.js backend server and HTML user interface (UI). Because this is a very straightforward codeset, it will serve as good context. The source code can be found here.
The build process is powered by a very impressive node.js package called electron-builder which also available on GitHub.
The first step is to set up a custom configuration section in package.json containing options for electron-builder:
The details of each option can be found on GitHub, but the most significant are those specific to the different operating systems including target types. We specify an installation executable (.exe) for Windows, an application image package (.AppImage) for Linux, and a disk image (.dmg) for macOS.
Next, we create the logic that will consume these options and create the installation files. This is done in electronBuilder.js:
Here, the code builds for the current development operating system (more on this later) by calling builder.build() which returns a promise.
When the promise completes it fires the callback method and passes the created file path as an argument. This project is using express as the web server with its route handling defined in routes.js. So, we add a new route specifically for downloading the Electron installation file that uses the above code:
Finally, we need to create a button on the install.html page so the user can trigger the build process and download:
When clicked, the button will open the REST endpoint http://localhost:5000/electron and trigger the build process; this will take a minute or two. When the file is ready the server will send the install package as a response and prompt the user to download:
At this point, they simply run the application as they would any other in their operating system and follow the instructions. For Windows, we see:
For Linux, since we are compiling to an AppImage file there is no installation process other than enabling execution:
And for macOS, we mount the dmg file and run the application:
And now we have the same application running in each operating system! Of course, in production it makes little sense to build the file every time a download request is made if the application has not changed. More likely, we would set this up as a post-processing step after deploying a new version so it is always ready to go.
Also, we did not cover the option of having electron-builder create all three deployment packages simultaneously. While this is simple to configure, it does impose one major limitation to the build process: it will require a physical machine running macOS as Apple puts restrictions on what can build native applications. Window and Linux, however, have no restrictions and can be created in other operating systems when properly configured. So, one option is to simply restrict all building to an Apple computer. Another, more robust, option may be to create a REST service running on a dedicated Apple machine that can be called to build the file after providing content.
Have you used electron to build a single app that works across multiple platforms?