Creating Javascript Binaries For Electron

Javascript is not a compiled language. It was designed to be portable and simple, interpreted and compiled by the browser at run-time – sometimes referred to as just-in-time (JIT) compilation. Yet, over time, Javascript has become a full-fledged application programming language, used first in server environments (usually in the form of Node.js) and now more and more for creating desktop apps (often using the Electron framework) and mobile apps as well (using a variety of frameworks).

However, as a non-compiled language, most Javascript code ends up “out there” for the world to see. One of the first steps along the path for most web developers is to “view source” on a website and start digging around in the code. This is fine for a website where their product is their content. But if we want to create a software product, Javascript is at a disadvantage because we cannot hide our code.

By contrast, compiled code is converted to binary – the language that the computer processor speaks. This is how applications created with most “professional” programming languages are distributed. The source code is not distributed with the application. It is impossible for another developer to open the binary and recreate the source which created it. Generally speaking, binary code is hidden and protected.

Can we create binaries from Javascript?

The title of this article is “Creating Javascript Binaries For Electron” – so… can we create Javascript binaries? Yes and no. Like HTML and CSS, most front-end Javascript developers are developing for the web – which means having to target multiple browsers and multiple operating systems. So Javascript is delivered as text, which is then interpreted and compiled by the browser. So if you’re developing Javascript for the web, the answer is “no.” If you want to deliver cross-browser binaries, you’ll need to look into WebAssembly, which is usually written in C/C++, Rust, or another language.

But Javascript is compiled. It is compiled by the browser at the time of execution by the browser’s Javascript “engine.” Different browsers use different engines (and different versions of the same engine), so we cannot distribute a binary without knowing the exact browser and browser version that will be running our code. This isn’t possible on the web. However, since Electron applications bundle Chromium (the Chrome browser) as part of their distributions, we do know the exact Javascript engine that will be running the code.

Can we create JS binaries for Electron?

As you may have guessed: Yes! 

Electron uses its own variant of the V8 engine for Javascript interpretation. Node.js has access to V8 functions and is able to access the binary cache file. Bytenode is a library created by Osama Abbas which facilitates saving and loading of these binary files for execution. You can use it on servers and in situations where you can determine the version of V8 that it will be running on. I’ve recently written Electron support for Bytenode so that it can output binaries which will run on Electron’s unique version of the V8 engine.

I’ve also sponsored development a new Bytenode Webpack Plugin to do all the hard work of compiling your Electron code and bundling it for distribution (without including the original source). Herbert Treis Neto developed it and I think it’s a breakthrough for Electron. It allows you to convert your entire Javascript application codebase to binary before distribution.

The caveats:

  1. Bytenode needs access to Node.js’ V8 functions in order to read the binaries. This will work just fine for your main process and any preload scripts. But you’ll need to enable nodeIntegration for webPreferences in your BrowserWindows. Alternately, you can usually move most of your renderer Javascript into a preload script wrapped around a document.addEventListener('DOMContentLoaded') listener. You’ll also need to set contextIsolation to false, or come up with a more elegant workaround.

  2. The Bytenode Webpack Plugin will create conventional text-based Javascript “loader” files for each entry point which load the binaries. These are not compiled… but they also were not part of your original source code.

  3. There are a few known issues with Bytenode. The main one to be aware of is that asynchronous arrow functions will cause crashes when used in rendering process code. You can simply convert these to function calls, or you could code in Typescript and output ES5, or you could use the Webpack babel-loader plugin to transform your arrow functions.

  4. It looks like Electron is deprecating Node’s V8 library in the render process beginning with Electron 12. Bytenode still works for now, but we’re be keeping an eye on this.

How do I get started?

I’ve created an Electron Bytenode Example repository on GitHub. Start there! It uses Electron Forge along with Webpack to bundle applications suitable for distribution. Follow the README instructions and you should be up and running quickly.

Links:

  • Electron Bytenode Example - a boilerplate “Hello World” example of an Electron app running on Bytenode, built with Webpack via Electron Forge

  • Bytenode Webpack Plugin - the Webpack plugin which makes all of this easy

  • Bytenode - the library which converts your Javascript code to binary and loads the binary files for execution at run time

We think we’ve ironed out most of the kinks, but if you find issues with any of these packages, please submit issues. Or better yet, create a pull request and contribute!

When I started developing a commercial Electron application, this was the missing piece of the puzzle. How do you distribute your application without distributing its source code? Now we have an easy-to-implement solution! I’m really proud of what we’ve built and I’m happy to share it with the Electron development community.

~

Are you an Electron, Node, or front-end developer? Want to help make awesome software to help awesome musicians and performers put on awesome shows? We’re hiring!

markus-spiske-Fa0pTKuoDVY-unsplash.jpg

When he’s not writing code, Jeff Robbins is a business coach, mentor, and virtual business partner who works one-on-one with company owners and leaders to help them build vision and direction for their companies while building productivity, stability, and happiness for their employees and themselves. You can work with him too. Reach out to set up a free session.