Electron: Why? Why not? (Building a password manager, part 1)
Electron is a framework to build “desktop” applications using Chrome(/ium) and Node.js, probably most notably used by the Atom editor (for which it was created). It does, however, regularly attract criticism on social media, so I figured we’d share our experiences with it, and why we picked it for our password management client.
The question of nativity
This can be a great feature, or its biggest drawback:
- It allows web-centric companies (like ours) to create native-ish applications without having to learn native toolkits
- …which will work on all major desktop OSes
- but will never look native in either of them (although some themes come close)
- yet allows you to go beyond the restrictions of native toolkits.
In our case, we didn’t have any developers really experienced in native GUI application development (the less said about my experiments 6+ years ago, the better), but have a team of decent web developers. It just doesn’t make sense under these conditions to re-tool everything for native toolkits, especially since the selection of native-widget-using multi-platform toolkits is less than ideal: WxWidgets looks so out of place that most examples in their own screenshot showcase can be used as case study in How To Make Apps That Look Out Of Place Everywhere. GTK3 is a pain even in Linux (somehow its CSS-based themeing system is more brittle and prone to break than GTK2’s old “C-libraries-and-config-files” system), never mind Windows or OSX. Qt, which offers their own brand of DOM+JS based UIs with Qt Quick, comes closest, but even it struggles with usability problems in OSX, both with Qt Quick and legacy widgets.
If you want to deliver a high-quality native User Experience (UX) under every major operating system (what is a native UX in Windows, anyway? Judging by the pre-installed applications in Windows 10, not even Microsoft knows at this point,) none of the cross-platform solutions are really going to cut it without substantial tweaks and optimizations, and going fully native is a lot of effort.
So why not use HTML? The first steps are slightly more painful (hopefully we’ll see more native themes for the big platforms), but once it gets to the small details of honing UX workflows, HTML/CSS/JS are much more flexible and allow rapid iteration.
That said, I don’t see Electron replacing native toolkits in existing programs — native toolkits are still unbeatable in terms of raw performance and integration.
Apart from the UI, there’s the question of the underlying code. Ignoring the inevitable language debate for a moment (getting even more fun and exciting the more platforms you want to support), security issues can happen in all of them (least likely in your favorite language, I know).
Due to being based off Chromium, Electron has rather extensive sandboxingavailable, making it harder (although not impossible) for attackers to compromise a user’s machine further if they somehow succeed in exploiting an application.
Other sandboxing approaches exist, but somehow OS vendors want to convince us that sandboxing is only possible when using app stores (UWP, Mac App store, etc.). Holding your users hostage to extort money from application vendors so they opt into app stores (and the 30 percent app store tax) just to make their apps less exploitable is rather questionable behavior, and I see no reason to support it.
In addition to Chrome’s sandboxing, Electron supports additional restrictionsto lock down webviews even further, although sadly disabled by default. I’d like to see a more locked down approach by default; it’s far better to make developers think about enabling exceptions than making them lock down their apps post-hoc.
Nodejs: The good, the bad, and the extremely ugly
Now back to the inevitable language debate. To be honest, I could do without nodejs on the backend and would be much more partial to other solutions (Python? C#? Go? Anything, really), but given the whole web-dev angle of Electron, I can understand the choice.
On the downside, you have to deal with the insanity that is npm and the node community’s library-itis (we need no less than 370 “unique” “libraries”, 38 of them multiple times, just for the Electron development environment, among them three different versions of a library that is ‘rm -rf for node’.)
Honestly, I have no good answer for it (or an opinion that can be considered printable). It’s the big, big disadvantage of the “modern web” tooling, and another reason why I don’t see Electron as an option to replace native code in established projects.
Performance and efficiency
The usual response to mentioning Electron on Hacker News et al. is something along the lines of “now I know why I bought 16 GB RAM,” no doubt inspired by Chrome’s RAM efficiency — or rather, lack thereof.
However, most of that comes due to the aforementioned sandboxing: splitting your program into multiple independent processes that cannot share memory pages always comes at a penalty to memory efficiency, but it’smuch more pronounced in a multi-tab application like Chrome where having 200 open tabs is not unheard of than in a single-tab (or indeed single-document) app.
Electron does come at an overhead, but it’s manageable: a blank “hello world” app comes at some 80 MB RAM usage across all its processes, compared to 40 MB for a blank “hello world” in Qt5 with classic widgets, and 55MB with Quickcontrols2. After that it’s up to developer discipline to keep the memory usage manageable.
Actual application performance is reasonable. UI snappiness will vary wildly depending on how much you torture the DOM, but web workers and the ability to move performance-critical sections to native libraries make general heavy lifting a solvable problem by shoving it into their threads, and modern UI frameworks tend to have good performance if you’re careful.
This is, to me, the one advantage of Electron: Electron-builder and the underlying Squirrel are surprisingly decent frameworks to roll out installers and update management for Windows and OSX (and give you Linux packages for the usual suspects) with only minimal preparation, doing all the heavy lifting (checking for and downloading updates, including signature verification, as well [un]installation) automatically, and the server side is easily handled as well.
Only the Linux builds are somewhat lacking. Installing to
/opt by default is a big no-no, and bundling all dependencies into one huge blob is not standard procedure for Linux distributions. That said, given the (sur)realities of the npm ecosystem, I’m not sure it would ever work out otherwise.
That’s why we chose it for the client of our password manager: being able to create one unified application for deployment on all operating systems that has a reasonably good, modern UX, while keeping all security critical code in a native library, and sandboxing it all was far too tempting a combination.