Hackernoon logoElectron: The Bad Parts by@philipp_lgh

Electron: The Bad Parts

Author profile picture

@philipp_lghPhilipp Langhans

Most cross platform programming languages and frameworks contain good and bad parts. Electron probably has more than its share of the goodbut also hides some dark secrets under its shining facade.

While the first impression of Electron might be that it solves all the problems related to cross platform development the reality is that many things wont work out of the box and they probably cant. It took me quite some time to understand this, and it took even more time until I had all the DIY solutions in place to provide users with things like correct installers, updates, a feedback mechanism.

This list of features on the Electron webpage is setting high expectations

Im a big fan of Electron and thought the following list could be very helpful for people who are new to the topic. But project managers who are evaluating different stacks and want to avoid surprises should benefit as well. The list presents things that are not completely clear in the beginning. Things where its worth to spend some extra time on evaluation before a decision and long term commitment is made.

Installers

Once the coding is over and the release planning starts, the first tough decision is waiting. One can either use the installer and update mechanism as described in the Electron documentation or use the installer and update mechanism that one of the best builder tools (electron-builder) recommends.

The official Electron documentation suggests the Squirrel (Windows and Mac) installer and the built-in autoUpdater. An open source release server (Nuts) is available which handles the server side management of updates and releases.

The other option is electron-builders own update mechanism electron-updater. It is based on the established NSIS installer (Windows) and plain old mac packages. electron-builder uses this approach as the default setting for all generated installers.

Quite frankly switching to NSIS by default seems like a very drastic move considering the Electron project still recommends Squirrel for Windows.

The Electron and electron-builder project do very much disagree on which solution is better. This leads to a tricky situation where devs have to decide between one official solution (which many consider to be complicated and not flexible enough) and a simple and powerful one that has built-in tool support. Personally, I think electron-builder is a blessing if you actually plan to provide installations of your software to millions of people around the world and you dont know where to start. It can save you weeks if not months of development and I would consider it to be an essential part of the ecosystem.

Here is a list of pros from the electron-builder/electron-updater docs that should be considered before one solution is chosen over the other:

  • It doesnt require a dedicated release server.
  • Code signature validation not only on macOS, but also on Windows.
  • electron-builder produces and publishes all required metadata files and artifacts.
  • Download progress supported on all platforms, including macOS.
  • Staged rollouts supported on all platforms, including macOS.
  • Actually, built-in autoUpdater is used inside on macOS.
  • Different providers supported out of the box (GitHub, Bintray, Amazon S3, generic HTTP(s) server).
  • You need only 2 lines of code to make it work.

Continuous Integration (CI) & Multi PlatformBuilds

Electron should not be confused with a pre-installed Java virtual machine. You will have to make (build, sign, distribute) your app cross platform. It wont be cross platform automatically.

From the electron-builder documentation

This can be quite confusing and shocking, but cheap and easy multi platform builds are a myth. It is almost ironical how often one will find cross platform Electron applications that are only for Mac or only for Windows. The reason is not that its complicated to write code for multiple platforms (Electron handles it amazingly well and the documentation is clear). The reason is simply that many developers do not have the big budget or access to other hardware to test and build on. Even worse: if you plan to be a legitimate developer your app needs to be signed and it might have one or more native dependencies.

The recommended solution in these cases is to get accounts for different CI providers: one for Mac (and Linux) and one for Windows. Why? Because Apple officially prohibits the use of their operating systems

  • in Virtual Machines on Non-OS X systems
  • on non-Apple Hardware

The result is that if your app is closed source it will cost twice as much to build for two OS. And if money and a complex build system is not and issue, you still have the issue that the app will only be tested and built on multiple systems. At this point it cannot be shipped yet. Signing your app remotely with an Extended Validation (EV) code signing certificate for example is pretty much impossible with all existing CI tools available since your certificate is bound to a physical hardware token which cannot / should not be transferred.

Size

The fact that each application comes with its own version of Chromium (the 20 million LOC, ~30MB [packaged] Web runtime) is one of the most criticised aspects. Fun fact: if you would decide today to build your own simplified competitor version from scratch it would probably take you 5,099 years to build. Some have tried to put Electron on diet and critics say it creates the feeling of installing a full operating system on top of an operating system. Every time.

not anissue

While many people would expect Chromium to drastically slow down the performance or consume precious RAM I havent experienced any of this in practice and havent heard bad feedback from thousands of test users. I guess it isnt such a big issue if you are used to have the Chrome browser running in background anyways. But here is the thing:

Not just installations bundle Chromium. Every update also comes with Chromium, Node and all the other Electron components unless the update is designed as delta or differential update.

Delta Updates

Everyone whos experienced a Windows update knows that updates suck! But they dont have to. Updates can introduce cool new stuff, dont have to interrupt the workflow and they can happen in the background instead of blocking your machine for one hourIm looking at you Microsoft. The is delta updates. Instead of uninstalling and re-installing everything, only the relevant parts should be updated incrementally.

The challenge: how to switch versions without the user noticing it (inspired by Developing an ElectronEdge)

Imagine the example from this blog: A class of students is trying out a software and the update is 70MB big. 30 people start their computers and get presented with an update. They download the update simultanously resulting in 2.1GB. Now, compare this to a delta update, handled in background, which is only 100KB in size and brings down the initial 2.1GB to 3MB total. It will shorten the time each student is waiting for the update to write itself to disk, to register with the system after the download; and it takes load from servers, saves bandwith, saves $$$, creates happy students and teachers.

Squirrel, in theory, supports delta updates. As of last week, electron builder with NSIS provides a beta solution for this too. However, I wouldn call either one of them to be available out of the box.

One of the applications Im working onAutobeat Playeruses its own delta update mechanism which updates the whole app. The twist: the whole application without external modules and libraries is only ~750KB(!) in size. Whenever I mention this, the reactions are priceless. Most people cannot believe the small size considering the feature richness and complexity of the application. A whole desktop application that has the size of a single image is how I would describe a new generation of (Electron) desktop apps. And the way weve implemented updates in Autobeat is straighforward and no rocket science.

Everything that can be remotely considered static is not part of the application image: jQuery, Font Awesome, Bootstrap, or all the other frontend libraries and any of the node modules are not part of the app itself.

If one strips everything that is not frequently changing such as these libraries and only updates the app logic partthe things youre actually working ona 99.9% size decrease is absolutely possible. However, it requires custom update logic. There is no standard solution available. The benefit: in Autobeats case we can update the app as a whole as long as external dependencies are not changing which rarely happens. Updates take between 12 seconds and go often unnoticed. It is like updating a websiteafter a refresh it looks different. No need to worry that the deltas are miscalculated or parts are not working together as expected. Once in a while we add more dependencies and have to do a full 31MB update. But were making a long term bet here, assuming that these intervals get longer and longer while our regular release cycles can be as short as a couple of hours. And everyday we are learning more about how to leverage things that work for the Web and how to bring them to desktop to release more efficiently.

Security

The separation between app logic and libraries as described above unlocks another very powerful feature: it potentially allows to release a second app, which shares the same, existing core libraries and does not require the installation of another Chromium bundled package or the need to signand distribute a new installer. It creates an environment like a super-powered browser that supports jQuery, Vue, Font Awesome, Polymer and every other framework as well as all relevant node modules out of the box and minimizes the apps size. Think about it for a second.

In recent tests, our team has successfully launched other instant apps (<1MB) in a distributed, P2P fashion in a fraction of a second. In the same way one would start apps on a Chromecast powered TV, it is also possible to remotely load apps on other machines. When I realized that we had just launched a fully featured desktop software from a web server running on a smartphone it partly felt like creating the next generation of decentralised apps and partly like the next generation of viruses.

In the same way that browsers are able to load any website, Electron potentially can load as many apps as it wants without the need to re-install the runtime over and over again. And the more the line between Web and desktop gets blurred, the more challenges we face as users to protect our machines and data.

Electron can also load websites just like any other browser. There are even tools like the extremely popular nativefier that wrap existing websites. These native-website-apps can potentially activate the webcam or microphone, access the filesystem and create, delete, encrypt things as they wish, or send them to serversand most of the time this is intended. Eventually, the hosting server becomes the command and control server of a gigantic botnet.

Once you get your first million users, your auto updater is basically a botnet with a million nodes. With great power comes great responsibility.

Electron provides many protection mechanisms: The sandbox model can be activated, node integration can be turned off, preload scripts and webviews create local environments with different permissions... However, it concerns me that these desktop web apps evolve and distribute faster than our old security models. Things like installer signing and trusted authorities are in the process of becoming meaningless in a world where websites can be run as full-fledged apps outside their sandbox.

every time you download express, you favorite this exact tweet from Hot Pocketssatire by JordanScales

Recently, I was attending a talk from a well-funded startup that scans and analyzes npm modules for vulnerabilities to warn developers before they integrate them. When I asked if they would also consider npm module security in a desktop context the answer was that they havent looked into it and that it has no priority. But every module that we reference and install on a users machine comes with its own dependencies and we end up sharing the users trust and permissions with modules we lose track of and often dont even know. In a time where a single cyber attack such as the recent WannaCry ransomware can have a financial impact as high as $4 billion, we are facing complete new challenges. This gets especially concerning when you read about popular modules that retweet hot pocket ads in the background every time they are installed.

Code Protection

In the same way we want to protect users we might also want to protect our own and our companys work. Electron apps are usually distributed in asar container files. To retrieve the plain source code from an installation and its contained asar file is as simple as:

asar extract app.asar secret_source_code

Files dont get obfuscated, encrypted or protected by default which means someone who wants to temper with an app can pretty much receive the working copy of the repository. This makes Electron a very poor fit for commercial solutions.

The official Electron statement reads like this:

The idea is that any sort of built-in protection can be bypassed anyways (which is true) and would just steal resources from more important areas (which is true).

Our products use a couple of obfuscation and encryption techniques and are definitely not as sensitive as say your Ethereum tokens. But many struggle with protection so here is one simple example to achieve source code encryption during packaging:

const crypto = require('crypto')
var password = new Buffer(my secret password);
function transform(filename) {
return crypto.createCipher(aes-256-cbc, password);
}
asar.createPackageWithOptions(src, dest, { transform: transform }..)

Asars transform option allows to specify a stream transformer that is applied when the files are packed into the asar container. However at some point you will have to decrypt your files and this is where it gets really tricky. Also, if your static password leaks youre not winning anything. There are other options like creating a V8 snapshot or to use C++ binaries and one can definitely make it their battle as much as they want. The main takeaway here is that Electron provides close to no protection and every minute that you invest in security hopefully creates 5 minutes for a hacker.

More

If you have an Electron app yourself and you liked the article, would like to get another perspective, or if you think that something is missing, presented in the wrong way or inaccurate, please leave a comment, clap or contact me.

To keep this article short, Im thinking about compiling additional and more detailed material. Additional topics could be crash reporting, separation of main and renderer process logic, analytics, installer distribution, campaign tracking and reengaging users through notifications. If you are generally interested in more information please let me know:

Link to form: https://goo.gl/forms/cnXgxM8fmg60f4lX2

Links

Good electron overview guide: https://blog.dcpos.ch/how-to-make-your-electron-app-sexy

electron-builder: https://github.com/electron-userland/electron-builder

Official updater docs: https://electron.atom.io/docs/api/auto-updater/

electron-updater: https://www.electron.build/auto-update

Squirrel to NSIS migration: https://github.com/electron-userland/electron-builder/issues/837

Multi platform builds: https://www.electron.build/multi-platform-build

electron-builder delta update support: https://github.com/electron-userland/electron-builder/issues/1523

Source code protection: https://github.com/electron/electron/issues/3041

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!