Electron Apps Are Getting Safer to Use
Electron is now poised for the enterpriseby Joe Honton
Electron desktop applications are created using technologies that are familiar to millions of software developers. This makes for a low entry barrier, and accounts for much of its appeal. Getting started is easy. Anyone familiar with Node.js can bootstrap a Hello World! desktop app with minimal fuss.
Of course there's also the other big draw: that the same codebase can be used to simultaneously target Windows, Mac and Linux. It all adds up to a compelling case for taking a closer look.
But creating a real Electron app is not for the faint of heart. Transforming that initial Hello World! into something fast and safe takes effort. Thankfully, performance and security are the big news items for Electron in 2020.
2019 — An Inflection Year
Several significant events occurred over the past year, bringing about an inflection point in the project. Last year's journey passed these major milestones:
- Regular releases began in earnest, with version 4.0 kicking off the new year, version 5.0 arriving in April, version 6.0 in July, and version 7.0 in October.
- In March, Electron adopted a governance structure, to formally lay out the rules of the road and to help make forward progress easier to achieve.
- In November, a fresh build process was unveiled by Charles Kerr and team, which dramatically shortens the time it takes to rebuild Electron when its dependencies (Node.js, V8, and Chromium) change.
It's beginning to feel like the joy ride of 2014 has settled into a more cadenced long haul.
Some people know that the recently release Brave browser began life as an experimental Electron project. After giving it a serious try, the Brave team eventually realized that no amount of lock-down code was going to allow them to safely access arbitrary URLs which could potentially contain malicious code. The lesson for the rest of the Electron community was clear: use Electron's embedded Chromium browser windows to display locally hosted pages only.
The scary part in all of this is that Electron's embedded Node.js library gives developers full access to the desktop's file system and networking stack. This is what distinguishes Electron desktop applications from simple browser apps. So to reduce the risk of malicious code running amok, developers can enable the
sandbox option for any browser window that doesn't need Node.js. Sandboxing works at the level of the host operating system. It's the sledgehammer approach to lock-downs.
Developers who need Node.js and decide to keep the
sandbox option off, can still play it safe by properly setting the
- When creating a browser window that accesses locally hosted documents which use only locally hosted resources (scripts, style sheets, images or fonts),
nodeIntegrationcan safely be set to
true, allowing Node.js library calls.
- On the other hand, when creating a browser window that may access arbitrary remote URLs,
nodeIntegrationmust always be set to
false, blocking Node.js library calls.
When select access to Node.js is still needed in a browser window with
nodeIntegration off, developers can make use of a
preload script can safely get and set file system and operating system values on behalf of the browser window.
For even more safety when accessing remote content, the
contextIsolation option can be set to
The Curious Proposal to Deprecate "Remote"
Electron is an open source project, and unlike many such projects it has no big corporate sponsor. Work is carried out by developers scattered across the globe working on projects with very different goals. So it should come as no surprise that contributors have focused on diverse needs.
Thankfully, one of those needs is better performance. To that end, at the recent 2020 Covalence Conference it was announced that the much used
remote module would be deprecated in Electron version 9.0, and removed entirely in version 10.0. This came as a surprise. Somehow I had missed seeing Jeremy Apthorp's previously published article Electron's "Remote" module considered harmful.
To understand the implications of this, newcomers need to appreciate that Electron applications have a split personality. On one side there's the application's main process, which is responsible for kick-starting everything. On the other side there are the application's renderer processes. The two communicate using inter-process communication (IPC).
The key to mastering Electron development is to understand how to use
ipcRenderer to coordinate everything. This is where the remote module comes in handy. It makes IPC calls from a renderer process to the main process super simple, allowing mere mortals to get more done.
In all of the Electron apps I'm involved with
remote.getGlobal() is used strategically and effectively. It works as expected every time.
The reasoning behind the vilification of
remote, and my own counter-points, are:
- Argument: It takes 0.1ms per IPC call. Counterpoint: This is peanuts. In the blink of an eye (at a frame rate of 16ms per screen refresh) 160 IPC calls could be made.
- Argument: It could lead to race conditions when used improperly. Counterpoint: Setting up callback listeners before execution eliminates this class of problems.
- Argument: Remote objects are proxied, and lose their prototype chain. Counterpoint: Proper deserialization and casting to the correct object type allows the result to be used without surprises.
- Argument: It's a security vulnerability waiting to happen. Counterpoint: This is not a germane argument. PNG images coming from the main process could have deployed their malicious payloads irrespective of any IPC call.
I personally think this is taking performance a bit too far, and hope that the plan to deprecate the
remote module isn't carried out. Still, I do appreciate the attention to detail. It's nice to know that Electron performance tuning has reached a level where 0.1ms is considered important.
Poised for the Enterprise
One thing I noticed at this year's conference was the trend towards using Electron for enterprise desktop applications, especially those targeting Windows users. Amid all the hullabaloo surrounding Electron's cross-platform capabilities, the point was missed that you don't have to target all three. I spoke with numerous people at the conference who were specifically limiting their development efforts to optimize for the Windows audience. Terry Thorsen, of ChartIQ presented the case well.
But to really pull this off the Electron community will need to start soliciting feedback directly from enterprise users, and putting their needs on the roadmap.
A Roadmap for 2020
I haven't seen a roadmap for 2020 and beyond, but if the release cadence of last year is kept up we can expect to see versions 8, 9, 10 and 11 over the next twelve months. My personal wish list includes:
- Better application-layer support for inter-process communication (IPC). Since we can't use events or callbacks to cross the main/renderer divide, a large part of every Electron application is handling the scaffolding for passing data around. Currently everyone has to roll their own.
- Better support for application level variables. Since renderers need to get and set application state, it makes sense to have some dedicated state object that both the main process and the separate renderers can access. Presently this is all done with
remote.getGlobal(). It's primitive and gets the job done, but I'd vote for something more sophisticated.
- Tree-shaking. Electron apps are bloated with code that never gets called. A welcome addition to the final
asarbuild process would be a step that analyzed which files could be jettisoned. I realize that this might be a time consuming process, but I for one would use it without grumbling.
- An Electron lint tool. As the project grows, better ways of doing things will be discovered, and older ways deprecated. Having a tool to scan our application and suggest ways to improve it using these new features would make everyone's app faster and safer.