So, Electron is bad. Like, really bad. It’s basically Flash for the desktop. Write a native app instead. Okay, I get it. Most developers who actually care about their trade don’t like Electron apps. And they don’t miss any opportunity to express their disgust. And I get it. Moreover, I get their frustration.
Electron apps are everywhere. You can’t get around them. Most important software that we use on a daily basis is written using Electron. Microsoft Teams? Check. Slack? Check. VS Code? Check. Skype? Check. Obsidian? Check. Zettlr? Check. Electron is everywhere. And it’s not like that’s surprising: Electron is a framework, similar to, for example, Qt. It allows one to build a desktop app that works cross-platform. And that’s the important part here. Qt, like Electron, allows you to have one code base and create an app that works on any operating system. The benefits are clear: You write all the neat functionality once, and then you can have the framework do all the stuff behind the scenes concerning how the app should look on macOS, or on Linux, or on Windows. You are only concerned with making that one button do a specific thing, and let the framework present the button to your users.
Electron is Bad!
But what is the specific problem with Electron? After all, you won’t find many articles decrying the problems of Qt as you will find articles ranting about how Electron is just the most recent incarnation of the devil. In unison, these articles will tell you: It’s basically Chrome, so if you have Slack and Google Chrome installed, you have the very same app installed twice! And that’s a waste!
The specific problem of Electron, thus, is twofold: First, it’s the pure size: You won’t get an Electron app smaller than ~120MB. That mustn’t necessarily be a problem since most computers nowadays have abundant space for that. But then you have a second problem: RAM and CPU usage. And that’s what can drain your battery. Chrome is notoriously hungry for RAM, and it involves a lot of processes just to display your websites, so your processor will have an extraordinary amount of work to do. And the same holds true for Electron apps, since these are basically also just websites. The only difference? They ship with the app and thus work offline. But precisely there lies the problem, as I will argue below.
If you want to see what many people hate about Electron, have a look at your battery consumption and you will see a pattern:
As you can see: My macOS will regularly tell me that those apps are using significant energy (and only those!) which are using the Chromium browser. In other words: Google Chrome, and any Electron app. And that’s certainly a point of concern. But it is only one out of many different ones.
The Bloated Web
The point of departure for this story is the rabbit hole I was talking about in the abstract: That many people complain about Electron being heavy, bloated, and thus a bad example of app design. While googling, I stumbled upon a talk by Maciej Ceglowski titled “The Website Obesity Crisis”. In this talk, he tackles a common problem in a humorous way: That websites become bigger and bigger and bigger. Nowadays, the common website will load several Megabyte worth of images, JavaScript, and advertisement in the background. If you’re like me living in a country where ISPs regularly throttle your mobile data if you use it too much, you will certainly learn to distinguish the “good” from the “bad” websites – those that load even with reduced bandwidth, and those that don’t.
It can be extremely frustrating just trying to look something up and having to watch some fancy web-app load letter by letter. And that problem is certainly not getting better. There is a tendency to write bigger and bigger websites that make full use of all the neat features modern CSS and JavaScript enable you to do. And I mean, why shouldn’t you? You have almost unlimited power to create whatever you like with a website. A loading animation, a photo carousel, or, as I have done in the top-right corner of this page, a small animated toy-equaliser that is supposed to model an equaliser pattern as you know it from the realm of audio. The data is random, there is literally no added benefit from it except that it looks neat.
However, while I was adamant to keep the animation computationally reasonable so that it wouldn’t slow down page speed or make your computer’s fans cry, this does not hold true for most websites nowadays. We have so many animations, so many scripts executing in the background that a one-minute visit to a national newspaper’s website might produce the CO2-equivalent of boiling a kettle of tea. And that’s no joke, given how many minutes (rather, hours) we spend online every day.
Just yesterday, I discussed the Obesity Crisis-talk with a friend. He works at an advertising company and thus has to produce these ugly, obese websites on a daily basis. He told me that many clients actually want a website to be all over the place. A static website is apparently bad for business. Apparently, many people who need a website to serve as a storefront advertising the products of their companies want completely interactive “experiences” instead of what websites were once supposed to be: A bunch of text telling you what the website (or, rather, your business) is about.
I highly recommend a read of the Obesity Crisis-talk to get a feeling for how the modern web looks like from an analytical perspective. But for this article, let’s head back onto the main road: Electron.
Electron and the Decline of Native Apps
A few years ago, one of the internet’s more important people and the inventor of Markdown, John Gruber, wrote a blogpost titled “Electron and the Decline of Native Apps”. The argument can be summarised quickly: When the era of personal computing was still young, people wrote native software, but now everyone just uses Electron and that is bad.
To understand Gruber’s argument, it makes sense to quickly clarify what the difference between Electron apps and “native” apps is. A “native” app is called this way based on two definitions: First it is an app that has to be compiled, i.e. translated into machine code. This makes it much faster than interpreted languages that are being executed via a so-called interpreter. Native code is something that the operating system will simply take and stuff into the CPU. Interpreted code, however, must be read and executed by another program. That program basically takes the code and translates it into machine code at runtime, sometimes called “Just in Time” compilation. Electron is a framework that allows you to write a full program using only JavaScript – and JavaScript is an interpreted language. That means: Whenever you start Slack or Teams or Skype or whatever, this will only start up an interpreter – namely Node.js. And that will take care of taking your code and actually executing it.
A second, somewhat stricter way to define “native” would be to say that it’s an app written in and for the operating system it is supposed to run on. For example, a “native” macOS app would be an app that has been written in Swift, whereas a “native” Windows app would’ve been written in, e.g., C# (read: C-sharp). I personally tend to only distinguish “native apps” as being compiled into machine code and leave out this more narrow way of defining the term.
Be that as it may: Gruber lists many factors that make “native apps” superior to Electron, and I tend to agree with most of his points. The most important argument is this:
But the problem with Electron apps isn’t really Electron — it’s the decline in demand for well-made native Mac apps. And that is ominous. The biggest threat to the Mac isn’t iPads, Chromebooks, or Windows 2-in-1’s — it’s apathy towards what makes great Mac apps great.
What he means by this is that Electron apps – and bloated websites alike – completely sh** on established standards. Just try to use Slack like you would use, e.g., Apple Mail: A lot of the gestures you’re used to using simply don’t work – or at least they don’t work the way they should.
To give one example: Zettlr was, for the longest time, simply another Electron app that made use of custom styles and thus also completely defied how an app is supposed to work. For Zettlr 2.0, one of my big aims was to actually take a look at the interface guidelines created by Apple, Microsoft, and the GNOME project in order to rewrite the app so that it doesn’t just look like a native app, but actually works like a native app. A small example is the use of scrolling in macOS. You can not just scroll up and down, but also swipe to the left and the right. This is something completely foreign to Windows and a good example for the point I’m going to make.
Zettlr features a file manager that basically allows you to manage files just like in Finder or the Windows Explorer, but from within the app. And in there are one file tree that displays all files in a tree structure and one file list that displays files as a list. In order to mimick the macOS feeling, what I did was to listen for horizontal scroll events on the file manager. When the user thus scrolls to the left or right, you can actually swipe between file tree and file list. And I made sure this behaviour only applies to macOS, not to Windows or Linux, since it’s foreign to those platforms and would horribly confuse users. This is what Gruber referred to in his article.
With Great Power Comes Great Responsibility
Both bloated websites and crappy Electron apps point to a common problem: Since CSS and JavaScript have become so omnipotent, it is easy to abuse their power. You can completely restyle checkboxes so that they look like switches. You can also completely hide text fields. You can transform images into links and, heck – you can even perform three-dimensional transformations on your website!
Native apps always had severe limitations: Since there are only this many interface elements built into the software to write apps with, if you want a text field, you just take the OS’s default text field. Custom elements such as text fields that support syntax highlighting are extremely rare, and if you want these to work cross-platform, I think these libraries are even non-existent. So native apps are easy: You are so constrained in what you can do with your GUI and what you can’t that you will build an app that feels “right” to either macOS or Windows or Linux by design.
Electron does not have this limitation. Since you basically just render websites, you have every freedom to do whatever the f*** you want. And that’s a problem: If you know how to wield CSS, there is a certain tendency for you to become megalomaniac and perform animation wizardry just because you can – even if it is detrimental to the user experience.
When I started writing Electron apps, I regularly checked the Electron app directory to see what other people were doing with the framework. And I also tested out some of these apps. I remember one app very vividly: It was written in React and by someone with a clear design background. The whole app was interactive, everything was moving and – of course – it looked like a website, and not an app. But the real horror ensued when I opened the preferences: First, the app would completely blur, then, in a sliding animation, a dialog window would slide in from the bottom and at the same time fade in from transparent. The UI text was progressively washing in like waves on the shore, and I was able to witness the whole spectacle with about two frames per second. It was horrifying. And that taught me an important lesson: Just because you can, you don’t have to do stuff like this. After all: you’re not building a website, you’re building an app.
For instance, one of the early releases of Zettlr, when it still very much looked like a website, would also blur if you opened a dialog window. That was the only animation, but it was still sluggish. I brushed it off and thought “Nah, it’s probably just because I’m bad at programming” (definitely a true statement back then). But when I disabled the blur-effect out of curiosity, the app suddenly felt snappy as hell. It turns out, the blur filter basically takes a screenshot of the app, and then runs that through a Gaussian blur. And that is an extremely intensive computation. We’re talking fullscreen apps here, not a small area. And that taught me: “Be sparse with everything”.
With great power comes great responsibility, and many of those people who develop Electron apps simply have extremely powerful machines. And if your computer is premium, you tend to forget that not everyone is blessed with a four-thousand dollar hell-machine. And that leads to a bad experience for everyone else.
And I am pretty sure that this is the underlying reason for all of these articles stating that Electron is simply bad: Because most people who develop Electron apps have no empathy and don’t think it through. Only when you actively remind yourself that what you’re currently doing must look and feel native to the operating system can you write an Electron app that is neither sluggish, nor one hell of a battery-drainer, nor … well, simply unusable.
GUIs are Hard. Extremely Hard.
But where does this leave us? Should we just collectively abandon Electron and start writing native apps again? That won’t work. And I don’t say this because Microsoft completely lost their mind and began rewriting literally everything in Electron. I say it because Electron solves one of the hardest problem for programmers out there: GUIs.
Writing a Graphical User Interface, or short: GUI, is one of the most difficult tasks imaginable – especially if you want a cross-platform app. Certainly, with XCode (macOS) or Visual Studio (Windows) it’s pretty easy to write an app in a few days and launch it. But the resulting app will only run on one operating system. However, with more and more people abandoning Windows, you won’t get away with writing just for one platform. More and more people (like me) have one computer with one operating system at home, and another computer with another operating system (most likely Windows) in their office and want to use the same apps regardless of the operating system.
Electron allows you to write an app that is not bound to one platform. The promise of Electron is as simple as compelling: Write your code once and have it run on all operating systems imaginable. This means if you want to implement a button to do something, you write the code once and then just build the app for every operating system – fully automated.
If I were to write Zettlr using native code, I first needed to find a library that allows me to use native text fields, buttons, or windows on multiple platforms. And these libraries can be hell. For instance, when I started programming with C++, I used wxWidgets to create a cross-platform app, but writing wxWidgets code is a pain. Either it’s simple to implement a button, but then it’s extremely limited in what you can do with the element – or it’s insanely complex to implement a simple interface element. Qt, which I mentioned in the beginning, is easier – but it’s not native. You can see if a program has been written in Qt, because you will notice that the interface elements do not look right.
Electron – due to the designing flexibility of CSS – allows you to do all of that. The only task that is then left is for you to actually write a few different styles that make a button look native on all three major operating systems. Electron cannot save you from having to style the interface elements according to the standards for Windows, macOS, and Linux. But it certainly can make your job much easier.
At the end of the day, if you’re an Open Source developer like me and have limited time – because all of that is done in my free time – you have little choice but to use Electron if you want your app to be used by many people. I am regularly pondering the thought of how cool it would be if I could simply rewrite the app in Rust. But then, when I look what the state of GUI libraries in the Rust ecosystem is, my fears are always confirmed: it’s not ready yet.
GUIs are hard, and Electron is the only chance you have to write a visual application that ticks all the required boxes:
- [x] Graphical User Interface
- [x] Cross-Platform
- [x] Easy to Write
- [x] Native Look
And that’s why Electron is neither bad nor will it go away anytime soon. What is direly needed, however, is a new mindset for those who write Electron apps. We, as a collective, have to stop using CSS to the fullest extent and restrain ourselves to those styles that are necessary, because otherwise it will resemble an abuse of power. Writing GUIs in Electron is still hard as I had to learn while adapting Zettlr to native OS styles recently, but it’s not as hard as writing something in C++ and then having to murder your precompiler with pragmas to make it use those styles that are correct for the given target platform.
Conclusion
Where does this leave us? The critics of Electron are pointing towards an important problem: CSS and JavaScript have become incredibly powerful over the last twenty years. But to create a native feeling you won’t need most of their powers. Minimalism is key here. We have to restrict ourselves to rather basic shapes and colours, and refrain from adding animations. What is missing is a mindset, maybe even a work ethic that respects the simple fact that just because you’re using HTML and CSS you are not, in fact, writing some website.
No, when you’re using Electron what you do is write a program, not a website. Yes, HTML, CSS, and JavaScript were developed for websites. But today we can also leverage the power of this holy trinity of the internet to make desktop application development easier. But this means we have to change our mindset. Away from a website that must be branded and convey the self-image of the company its representing, and towards an app that must look native and be extremely fast. If you can’t or won’t restrain yourself then you shouldn’t be building Electron apps. And then, these criticisms are directed at you.
It won’t help to say “But Electron is bad :(“ since that is unfair towards all those who are developing in their free time and for whom Electron is a blessing. I’m pretty positive that if I hadn’t stumbled upon Electron back in 2017, Zettlr would not be. But we, as the Electron community, have to take those criticisms serious and strive to be better.
And it’s certainly possible. While I’m still not ready rewriting Zettlr to look 100% native and be extremely performant, what I noticed in the past six months is how much you can do just by caring. Making sure an app looks and feels native while remaining fast and snappy is definitely a hard task. But with Electron it’s doable. Much more so than having to maintain three different programs because you can’t program natively for Windows using Swift.