Leading the development of electron-react-boilerplate for over 5 years has taught me quite a bit about performance challenges with electron and optimizing electron apps. Contrary to popular belief, I believe electron apps can perform as well as native desktop apps.

Before reading this, it's important to recognize that applications will certainly benefit a lot more from fundamental architectural improvements as opposed to the optimizations discussed here. If you'd like to read more about architectural improvements, read the slack posts in the "Classic Electron and JS Perf Readings" section below.

Strategies for Performance Improvement

Over the course of maintaining electron-react-boilerplate, I've noted the following strategies as the most impactful improvements to be made to electron apps.

1. Always use a bundler

require() calls often bottleneck the initialization time of your app. The require algorithm is recursive and synchronous (so it blocks the main thread).

Sam Saccone, a performance engineer at Google, debugged Atom's startup performance:

Most of the startup time is spent requiring modules and deadlocked in node.js execution before the initial paint in the browser is ever fired, resulting in slow feeling startup experience for end users, by potentially bundling all of the dependencies into one file there could be a sizeable perf savings.
https://github.com/atom/atom/issues/9720#issue-118095913

atom require flamegraph

Don't go down this path. Use a bundler!

2. Defer non critical imports

This can be done in a number of ways. One way of reducing the up front cost of loading your application is to use route-based code splitting and an app shell architecture. While working as a consultant for companies that use electron-react-boilerplate, I've used route-based code splitting optimizations to bring down startup time from ~10sec to ~3sec.

3. Debug Devtools and Content Tracing

Applying traditional browser performance debugging techniques to Electron apps is a good starting point.
https://www.electronjs.org/docs/latest/api/content-tracing

tools

4. Fallback to WebAssembly or native node modules

If your app often performs computationally expensive tasks, its likely a good move to run those tasks in WebAssembly. WASM serves as a shortcut to the JavaScript engine's optimizer. Rather than the JavaScript engine having to execute and optimize code at runtime, WASM executables are optimized ahead of time and therefore provide much more deterministic performance characteristics.

5. V8 Snapshots

Snpashots are a feature of V8, Chrome's JS engine, which allows snapshotting an initialized heap and reusing it. This avoids reinitializing objects on the heap every time your app starts up. The V8 team wrote a great article on V8 Snapshots, which I highly recommend reading. I'd also recommend checking out electron-link, a tool that allows leveraging V8 Snapshots to improve electron's startup performance.

📚 More Readings

For those who want to read more in-depth articles on optimizing the performance of Electron and browser apps, I recommend checking out the case studies and perf readings below.

🙇‍♀️ Case Studies

📖 Classic Electron and JS Perf Readings