This article by Jian Yue SimpRead transcoding, original address getstream.io

Learn about the performance differences between Flutter and JavaScript when developing desktop applications a……

Flutter and JavaScript are the first choice for developers and engineering teams in the cross-platform space. This article explores the performance differences between Flutter and Electron, two solutions for getting your applications running on your desktop. Both are popular choices, but the performance differences are worth considering.

This article includes the following.

  • Underlying engines and technologies that support Flutter and Electron.
  • Important performance considerations and their relationship to Flutter Desktop and Electron.
  • Demonstrate the real performance metrics of the Flutter Desktop and Electron applications on macOS.

Before you continue, keep in mind that this article is not intended to promote one solution over another. There are enough resources on modern computers and devices to make it hard to tell the difference between a well-made Flutter desktop application and a well-made Electron application.

Performance is just one metric. The productivity, experience, and knowledge of the developers on your team are also important factors to consider when deciding which solution to use.

Disclaimer. The writer is the developer of Flutter for GetStream. IO. To ensure quality, JavaScript engineers reviewed the article. While every effort has been made to create an unbiased and fair comparison between the two technologies, there can be unintentional errors or incorrect measurements.

All of the code used for these tests is linked in the article; Please feel free to find errors or inconsistencies and help improve the quality of the results.

Electron and Flutter table status

Electron

Electron has stood the test of time and proved to be a good solution for bringing networking applications to the desktop. In fact, some of my favorite (and most-used) desktop apps run on Electron, like Visual Studio Code, Figma, and Slack. Other popular apps include Discord, Skype and Tusk.

Microsoft is moving Teams from Electron to Edge WebView2.

Source.Twitter.com/rishmsft/st…

These are big companies and big applications. Vast resources and engineering efforts have been devoted to improving Electron, NodeJS, V8 engines, JavaScript, HTML, and the entire web. Look at the work Microsoft has done to optimize VSCode to make it feel like a native application.

But for every good Electron application, there is a bad one (don’t name names 👀). The Electron application is known for its large executable file size, large memory/resource usage, and in some cases, long startup times and jank issues.

Flutter

Flutter has an ambitious goal of targeting devices from a single code base. Flutter has proven itself to be a good mobile (Android and iOS) development solution, and its performance has steadily improved since its V1 release. There have been some performance issues over the years, but most of them have been resolved.

Flutter Desktop, however, is still in beta at the time of writing this article. There is no big-name application made by Flutter Desktop, which we can experiment with and compare directly with Electron. Time will tell how good a solution it is in a production scenario, but from my personal experience, the initial performance results seem promising. In theory, a Flutter application that works well on mobile should also work well, or better, on the desktop.

A brief explanation of the JavaScript V8 engine and Dart Native

Let’s discuss the language and technology for driving Electron and Flutter.

JavaScript V8 engine

Electron combines Chromium’s rendering library with Node.js. Both share the same JavaScript engine, V8. Direct reference to V8 Docs.

V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and Node.js, among others.

V8 compiles and executes JavaScript source code, handles memory allocation for objects, and garbage collects objects it no longer needs. V8’s stop-the-world, generation, and precise garbage collector is one of the keys to V8 performance.

The V8 engine continues to improve, and while JavaScript is often thought of as an interpreted language, modern JavaScript engines no longer just interpret JavaScript, but compile it. V8 internally compiles JavaScript with just-in-time (JIT) compilation to speed up execution.

You can also use native modules to interconnect with native code (see the example in this article).

Dart Native

According to Dart Native Docs.

In development, a fast development cycle is critical to iteration. The Dart VIRTUAL machine provides a just-in-time compiler (JIT) with incremental recompilation (enabling hot reloading), a real-time metric set (enabling DevTools), and rich debugging support.

When an application is ready to be deployed into production — whether you publish to the app store or deploy to the production back end — the Dart AOT compiler can be pre-compiled into native ARM or X64 machine code. Aot-compiled applications have a consistent, short startup time at startup.

Aot-compiled code runs within an efficient Dart runtime that implements a robust Dart type system and manages memory using a fast object allocation and generation garbage collector.

The key takeaway is that Dart can give you a quick developer experience in the form of a hot reload and the benefit of a small compiled application to the target architecture when you create a release build.

Here are some other notable Dart features and updates.

  • Dart recently added support for sound space safety, which enables the Dart AOT compiler to produce faster machine code (see Dart and the performance benefits of sound types for more information).
  • Dart’s foreign Function interface (FFI) lets you use existing C libraries for better portability, with the option to use highly tuned C code for performance-critical tasks. Read Dart 2.13 to learn more about Dart FFI.

Dart is growing into a great language in its own right, but its popularity can definitely be attributed to the rise of Flutter. Dart is maintained by Google and the Flutter team, which means the team can optimize the framework (Flutter) and language (Dart) to help improve the developer experience.

Performance considerations

The following sections compare Flutter and Electron performance considerations. These are areas that can have an impact on the performance of the final application, or your developer experience and the amount of work required to avoid potential performance issues.

Both Flutter and Electron Docs cover the performance of each platform and you should check for this latest information.

Application size, dependencies, and modules

One important factor to consider is the executable size of the application you compile. Here Flutter is the clear winner. Flutter compiles to machine code, which means Dart can be smart about what to include and what to strip out when it finally builds. Take a look at this list of closed PR, relative to Dart’s AOT build size. This is an area of constant improvement and measurement.

The Electron application, on the other hand, runs on Chromium. Basically, each Electron application is bundled with its own browser. That’s the magic that makes Electron possible, but it’s also why you can find yourself in a simple “Hello, World!” You get an executable file of about 150MB (or more) in your application. A similar Flutter application is about 30MB. Later, in our performance metrics, we’ll look at some real numbers to assess package sizes.

Ignoring the sheer size of a Electron application, there are other important factors to consider.

  • In Electron, you need to be more careful about the modules you include, because unused code will still be included in your final package (see the section on accidentally including modules).
  • Loading modules in Electron is a surprisingly expensive operation. As a developer, you need to be careful to delay loading large modules until you need to (see the section loading and Running Code too early).
  • Finally, it is recommended that you bundle all your application code together, as running “require “is an expensive operation (there are various JavaScript bundlers that can help you do this, such as Webpack, Parcel, and rollup.js).

If you’re a hardcore JavaScript developer, you might rub your eyes and say, “It’s easy,” but these little annoyances add up. Especially if you’re a new developer.

Dart, on the other hand, does a good job of stripping away unwanted code and dependencies. If you start a new Flutter project, the build Settings running on macOS (and all other platforms) will already be set and waiting.

Flutter requires much less configuration, and when you build your application on the target platform, you will immediately benefit from all the AOT compilation benefits that Dart provides.

Isolators, network workers, and processes

Both the Flutter and Electron apps can unload expensive work from the Main/UI thread, which is necessary when you want to perform operations that might be UI blocking.

  • In Dart, each thread has its own memory in its own quarantine, and the only way different quarantines can communicate is by passing values through ports.
  • In Electron, you can use Worker Threads to enable thread usage to execute JavaScript in parallel.

For more information about these processes, see Electron’s Blocking the Main Process and Isolator and Event Loops for Flutter.

While both frameworks can perform expensive work in a non-blocking way, it’s important to note that Electron starts several extra processes by default because it’s running Chromium.

Take a look at this screenshot from **macOS Activity monitor.

The activity monitor shows the Electron “Hello, World “application on MacOS.

You’ll notice three additional Helper processes (Helper, GPU, Renderer), each of which takes up some memory and processing power.

  • The main process creates and manages BrowserWindow instances and various application events.
  • The renderer process that runs your application’s user interface (web page) is an instance of webContents.

Check out Cameron Notes’ excellent article for an in-depth look at Electron’s main process and renderer process. If you want more information, this is a good place to start.

Flutter, on the other hand, runs only one process, and you can choose to generate additional isolation programs to uninstall the main thread.

The activity monitor shows the Electron “Hello, World “application on macOS.

For more information about Flutter isolators, see the following article.

  • Dart is truly multithreaded
  • Lightweight isolators in Flutter (a video on how to use isolators to reduce the memory footprint of a Flutter application)

Apply colours to a drawing

These topics are beyond the scope of this article. But whether you’re using Flutter or the latest JavaScript SDK, it’s important to understand how your code translates into pixels on the screen.

If you want to learn more, here are some good resources.

  • Overview of Flutter architecture
  • How does the browser work: Render

Both Flutter and Chromium use Skia, a 2D graphics library, to handle rendering issues.

WebAssembly (Wasm)

A new machine code binary format designed specifically for browsers. Applications compiled into WebAssembly can run with JavaScript without affecting performance. Both Flutter and Electron applications can (and do) benefit from this technology.

From MDN Web Docs.

WebAssembly is a new type of code that can run in modern Web browsers — it’s a assembler like low-level language with a compact binary format that runs at near-native performance and provides a compilation target for languages like C/C++, C#, and Rust so they can run on the web. It is also designed to run with JavaScript so that the two can work together. . Using WebAssembly’s JavaScript APIs, you can load WebAssembly modules into a JavaScript application and share functionality between the two. This allows you to leverage the performance and power of WebAssembly and the expressiveness and flexibility of JavaScript in the same application, even if you don’t know how to write WebAssembly code.

It’s incredible. See the following articles to learn more about Wasm.

  • WebAssembly cut Figma’s load time by 3 times
  • Network support for Flutter
  • Flutter web uses WASM instead of dart2js
  • Dart and Wasm were used for experiments

Flutter and Chrome DevTools

Improving application performance is not a simple matter, and sometimes finding performance errors can be like looking for a needle in a haystack. To do that, you need the right tools to help you. Fortunately, both Flutter and Electron can use the fantastic DevTools.

For this category, Electron has the upper hand. Chrome DevTools is an advanced piece of software that has been in development for many years. Performance analysis, debugging, network monitoring, layout checking, and everything else is amazing.

Dart DevTools, while amazing, is still young. I personally enjoy using it and it gives you everything you need to debug your Flutter application, but there is definitely room for improvement.

The performance test

Now that we’ve discussed the important performance factors for each platform, let’s run some applications to see how Flutter Desktop and Electron compare.

These tests were only conducted on macOS Big Sur V11.5.2, on a MacBook Pro (16-inch, 2019) with the following specifications.

  • 2.3ghz 8-core Intel Core i9
  • AMD Radeon Pro 5500M 4GB
  • Intel UHD Graphics 630 1536 MB

The source code and installation instructions are available in the Github repository. We encourage you to run these tests yourself and do your own experiments. Please note that these are demos only.

You can optimize these examples in many different ways, both Flutter and Electron. This is just a performance comparison out of the box; What you can achieve with minimal developer effort.

In addition, running some of these performance tests results in profiling overhead. When the application is not parsed, the real-world results may be different.

You should also expect some variation between different runs. Ideally, you should run these tests multiple times and average them (this article doesn’t do that, just the first run).

⚠️ In these examples, **Electron Forge** is used to configure and run the Electron project. NPM version 7.23.0 is used. ⚠️ Flutter version 2.5.1 is used on stable channels. ⚠️ Note that Chromium limits frames per second (FPS). See Chrome’s Unlimited Frame Rate article for more information.

“Hello World” App!

One says “Hello, World!” Simple application.

The startup time of the application

Both Flutter and Electron can open and draw to the screen in a second, Flutter is slightly faster.

“Hello, world! Application, Flutter startup time comparison with Electron

The size of the executable

Here we can see that even for a simple application, the Electron app takes up a lot of space!

Flutter

  • Deployment target 10.11 and above. 37.3 MB
  • Deployment target version 11.0 or later: 22.7 MB

Electron

  • 183.9 MB

Activity monitoring

The Flutter uses the least memory (~ 38MB versus ~ 100MB). All of these extra Electron processes are going to add up.

memory

“Hello, World” Flutter app. Memory ~ 37.9 MB

“Hello, World” Electron app. Memory. ~99.6 MB (44.9 + 26.1 + 18 + 10.6) The CPU, GPU, and energy effects are not shown in this example.

Profiling/frames per second

A silly example, but included for fun. Here, the application’s window is resized to trigger rerendering.

As expected, both the Flutter and Electron run comfortably at 60fps. But note that Chromium limits the number of frames. That’s why Electron’s frame time is always around 16ms.

The Flutter is less than 3ms at 60fps per frame.

Flutter, 60fps, average frame count is below 3ms

The Electron is about 16-17 milliseconds per frame, 60 frames.

Electron, 60fps, average frame time set to 16-17ms

Lottie animation application

This example loads 150 Lottie animations and animates them all at the same time.

The startup time of the application

Here, the Electron application opens half a second before the Flutter application; However, the first full drawing is at the same time. It should be noted that Electron has a very noticeable frame drop in the first few seconds.

The startup time of Flutter and Electron for “Lottie Animations”

Executable size

Here, when using Electron, loading additional modules can result in a significant increase in the packet size (~ 80MB larger compared to the sample for “Hello, World “).

The Flutter application only increased by ~ 7MB after adding Lottie packages and animation files.

Flutter

  • Deployment target 10.11 and above. 40.7 MB
  • Deployment target version 11.0 or later: 29.1 MB

Electron

  • 259.1 MB

Activity monitoring

Flutter uses fewer resources in all categories. CPU, GPU, memory, and power.

The most striking result, however, is that the Electron version uses a lot of memory. Roughly 2.2GB, while the Flutter is 170MB.

CPU/GPU The CPU and GPU usage of Flutter are low. ~130% (CPU) and ~13% (GPU), while the Electron is ~215% (CPU) and 41% (GPU).

“Lottie” Flutter application. The CPU. ~ 130.6% and the GPU. ~ 12.8%

“Lottie” Electron app. The CPU. ~215% (0.2 + 101.6 + 113.4) and GPU. ~ 41%

memory

Compared to the Electron’s ~2.2GB, the memory usage of the Flutter is much lower, only ~170MB.

“Lottie” Flutter application. Memory. ~ 168.5 MB

“Lottie” Electron app. Memory. ~2261.3MB (2100 + 95.6 + 55.3 + 10.4)

Energy impact

Flutter uses less energy and has an effect of ~130, while Electron has an effect of ~220.

“Lottie” Flutter application. Energy: ~ 131.6

_”Lottie” Electron application. Energy: ~220.7 (0.2 + 137.8 + 82.7) _

Profiling/frames per second

In this example, there is a significant travel time difference between the Flutter and Electron. On startup, the Flutter runs immediately and remains stable at 40-45 FPS, while the Electron shows a noticeable drop in frames in the first few seconds and then stays at 20-25 FPS.

The Flutter varies from 10-30ms per frame, with an average of about 40-45fps.

“Lottie Animations “application. Flutter desktop profiling.

The Electron varies from 25 to 60ms per frame, with an average of about 20fps to 25 FPS.

“Lottie Animations “application. Electron.

High resolution image applications

This example loads 100 high-resolution images over the network, caches them, shrinks them down to a small size, and continuously rotates the image.

Note that on Flutter, the cached_network_image package is used to cache images between runs.

The startup time of the application

Both the Flutter and Electron open in a second, and the Flutter application opens and loads the image slightly faster. In Electron, there is a noticeable drop in frames in the first few seconds.

Compare the startup time of the Flutter desktop with Electron in the Spin Image application.

The size of the executable

The Electron application is exactly the same size as the “Hello, World “example. The Flutter application is 5MB in size and includes the image cache package.

Flutter

  • Deployment target 11.0 or higher: 27.7 MB

Electron

  • 183.9 MB

Activity monitoring

In this example, except for memory usage, the Flutter uses about 100MB less and the result is much closer.

CPU/GPU

The difference between Flutter and Electron is small. Flutter uses slightly fewer resources.

“Image” application Flutter. The CPU. ~ 13.6% and the GPU. ~ 2.97%

Image app Electron. The CPU. ~ 17.5% (1.1 + 7.7 + 8.7) and GPU ~2.8%.

memory

The Flutter uses about 100MB less than Electron.

“Image” application Flutter. Memory: ~ 73.5 MB.

Image app Electron. Memory. ~173.5 MB (74.2 + 54.4 + 29.1 + 15.8)

Impact energy

There is little difference between Flutter and Electron, with an energy effect between 12 and 17%.

“Image” application Flutter. Energy impact: ~12.5

Image app Electron. Energy impact: ~17 (1.1 + 8.4 + 7.5)

Profiling/frames per second

The Electron version has a noticeable drop in frames when the application starts. But after the first few seconds, both run at 60fps, no problem.

Flutter

Except for the occasional frame drop, its rendering speed is close to 1ms per frame. An easy 60fps.

“Image” application Flutter. One millisecond per frame, 60fps.

The Electron forces each frame to be 16ms and 60fps.

Image app Electron. Set the frame rate to 16ms, 60fps. However, the number of frames dropped significantly when the application started.

conclusion

You must draw your own conclusions from the data provided 🙂. Both are great cross-platform options if you want to bring your application to the desktop.

The following is a summary of the findings.

Electron

  • As Electron grows, it can struggle with startup time and drawing time for the first time. However, apps like VSCode and Figma prove that this can be avoided.
  • Electron proved to be a viable solution; If you can write a fast and high-performance web application, you can do the same on Electron.
  • Has a large installation size and memory usage.
  • You need to pay more attention to what modules you include, when they are loaded, and how your application is packaged.
  • Wasm integration can greatly improve some tasks.

Flutter

  • Flutter Desktop is still in Beta and has not been validated on a wider scale.
  • The Flutter will have a smaller memory footprint and installation size. These numbers are also likely to improve, especially as Dart continues to be optimized.
  • Targeting multiple platforms is easy and requires minimal developer staffing.
  • Flutter platform integration and FFI are great solutions.
  • Dart’s NULL Safety and its potential integration with Wasm are the icing on the cake for Flutter.

In terms of performance experiments, it would be great to be able to demonstrate two large, similar Flutter and Electron applications side by side and be able to compare more real-world scenarios.

This will be an interesting conversation to have once the desktop application of Flutter begins to appear.


www.deepl.com translation