Electron at Wagon
July 15, 2015 | Mark Daly

While building Wagon, we’ve encountered a few engineering challenges that aren’t easily solved in the browser. Our users want Wagon to connect securely to their database and analyze large amounts of data, while being easy to setup and always up to date. Unfortunately, browsers can’t connect directly to databases and aren’t optimized for processing millions of data results. The standard web browser won’t suffice, so what should we do?

As many companies are discovering, mixing web and native technologies is very compelling. Early adopters including Slack, Atom, Quip, Visual Studio, Spotify, MapBox, Front, and Nylas have found ways to weave these once unrelated approaches.

At Wagon, we’re using Github’s Electron (previously “Atom-Shell”) as our underlying app framework. Electron was carved out of the Atom editor project and lets us deploy web UIs to the desktop. Our CTO Mike described Wagon’s technical architecture: a Javascript application for user experience along with a native process for database connections and streaming data computation. We want a capable desktop application with the ease of developing for the web.


Electron


The earliest alpha of Wagon was a command line program that powered a browser app available at localhost. We soon shipped our first Mac app: a download-able, double-click-able version using MacGap. As more people used Wagon, we wanted to update the code silently in the background, deploy to Windows and Linux, and move away from WebKit (we <3 Chromium’s dev tools!). We frequently ship new versions of both the JS and compiled Haskell, and it was painful for our users to manually download and reinstall the application. We briefly considered Mac-specific update mechanisms but it became clear we needed to replace MacGap. In searching for a full-featured, cross-platform web-view container, we found Electron.


Wagon's Electron architecture diagram
Wagon uses Electron to bundle native and web technologies


Electron is based on Chromium, runs on multiple platforms, and comes packaged with useful features like desktop notifications, custom keyboard shortcuts, and native menus. Auto-update, which originally motivated us to try Electron, is easy to set up and simplifies shipping new versions. Electron is evolving quickly and openly, supported by its vibrant community, active development, public Slack room, and commercial backing.

Migrating from MacGap to Electron was straightforward, as Electron’s excellent documentation has instructions on rebranding, packaging, and distribution–we got a prototype up and running on a Friday afternoon. Electron differs from other web-view containers by using Node.js (via io.js) as its entry point: when an Electron app starts, execution begins in a JS program included in the app bundle, which can open windows and interact with the host OS. Node’s and Electron’s rich JS APIs made porting from MacGap easy, and we’ve added features that would otherwise only be possible in a native application (like custom menus and dialogs).

Our static assets are hosted on CloudFront, so we can update the UI without requiring users to redownload the whole application. However, it can take a few seconds for these assets to load and we want an immediate cue that Wagon is working. Here’s how Wagon ensures a smooth app launch experience:

  1. On app start, the main Node process runs our JS App Loader. It loads configuration files, starts background tasks, and opens a renderer to load the latest UI.
  2. The renderer immediately displays a splash.html page that is shipped with the Wagon.app bundle.
  3. The splash page uses Electron’s <webview> tag to load our remote assets and start the JS app in the background while the Wagon logo rolls (some say dances!) on screen.
  4. Once the UI is ready, it notifies the splash page via Electron’s IPC API.
  5. The splash page swaps its content for the UI, creating a seamless transition into the full application.

When we’re ready to roll out a new version of Wagon.app, we use an automated deployment approach built on GitHub and CircleCI. When we merge a pull request into the master or production branches of our repos, CircleCI automatically builds the application bundle. The components are dropped into the Electron app structure, code-signed, and uploaded to S3. CircleCI also updates a configuration file that our auto-updater API endpoint reads, which lets us notify running instances of Wagon that a new version is available. The update is automatically downloaded in the background, installed, and triggers a desktop notification for the user.

We believe that great software should run in the browser, on phones, and on the desktop. If building across these platforms sounds exciting, check out our open positions, and email us or tweet @WagonHQ. Gogogo!