Add Electron migration post
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: "I was wrong about Electron"
|
||||
description: "Why I migrated Paseo from Tauri to Electron after the small-binary story stopped mattering more than rendering, notifications, and bundling a Node daemon."
|
||||
date: "2026-05-28"
|
||||
draft: "false"
|
||||
---
|
||||
|
||||
When I started building Paseo, I picked Tauri.
|
||||
|
||||
The reasoning felt obvious at the time. I was building a desktop app with a web UI, and I cared about shipping something that did not feel bloated. Like a lot of developers, I had also internalized the idea that Electron was the bad option.
|
||||
|
||||
Tauri had all the right stuff: Rust, tiny binaries, native webviews, lower memory usage. It felt like the tasteful choice. I thought I knew better than all those other Electron apps.
|
||||
|
||||
You see this attitude everywhere. Products put "Built with Tauri" on their landing pages as if the framework itself is a selling point. I bought into that more than I realized.
|
||||
|
||||
At first, it felt like I was right. On macOS, the app was small, the UI worked well, and the bundle size made the decision feel obviously correct.
|
||||
|
||||
Windows did not really challenge that either. Tauri uses WebView2 there, which is Chromium-based, so the app behaved close enough to what I expected. There were platform details to deal with, but nothing that changed my mind.
|
||||
|
||||
Linux is where things started getting complicated.
|
||||
|
||||
Tauri does not bundle one browser engine across platforms. That is the point. On Linux, it relies on WebKitGTK, which sounds elegant until you are debugging rendering behavior across distros, GPU setups, and Wayland/X11 differences.
|
||||
|
||||
For Paseo, this turned into a lot of product work I did not want to be doing. The WebKitGTK bindings Tauri was using were too old. Wayland had problems. And once I got the app running, it just looked different. Not slightly different in the way you expect across platforms, and not only small things like font weights. Some screens had real layout differences.
|
||||
|
||||
I could maybe have lived with all of this, but then I started implementing notifications.
|
||||
|
||||
For Paseo, notifications are not a nice to have. If an agent finishes, fails, or needs attention, I want the user to click the notification and land in the right place.
|
||||
|
||||
Tauri's notification plugin can show notifications, but desktop click handling was not there in the way I needed. The Actions API exists, but the docs mark it as mobile-only, which was strange.
|
||||
|
||||
I noticed Tauri was expanding into mobile apps too. I get why that is exciting for the project, and I am not saying they should not do it. But from where I was sitting, it was hard not to feel some doubt. I was still fighting basic desktop product issues while the framework was moving into a much larger surface area.
|
||||
|
||||
I got notification clicks working by writing platform-specific code, but it was not straightforward, and now I had to maintain it. By then the pattern was familiar: the app needed a normal desktop behavior, and I was writing the missing glue myself.
|
||||
|
||||
There was also the daemon. This part is not really Tauri's fault, but it pushed me further toward Electron.
|
||||
|
||||
Paseo has a Node.js daemon, and I wanted a one-click experience. Download the app, open it, and go. No separate Node install. No manual daemon setup. No "run this command first."
|
||||
|
||||
Tauri supports sidecars, so I got the daemon bundled and it worked. But it became its own project: different binaries for different platforms and target triples, packaging details, permissions, process spawning, paths, upgrades. None of it was impossible. That was almost the problem. I kept making it work while slowly building around the framework instead of with it.
|
||||
|
||||
At some point I had the realization that I was building Electron with extra steps.
|
||||
|
||||
I decided to try Electron. The migration was a bit of a pain, but I got things working surprisingly fast, and after a week of solid work Paseo actually felt lighter and simpler. The UI looked the same across platforms. Notifications behaved the way I needed. The daemon fit naturally because Node was already there.
|
||||
|
||||
The app got bigger, obviously. Electron ships Chromium and Node. That is the tradeoff everyone knows about.
|
||||
|
||||
What I had missed was that app size was not the tradeoff that mattered most for Paseo. This is a development environment with a web UI, a local daemon, terminals, agents, process management, notifications, permissions, and long-running state. I need it to behave predictably on macOS, Windows, and Linux more than I need a small bundle.
|
||||
|
||||
I still think Tauri is appealing. If your app is mostly a Rust app with a web UI, or if you are staying on one platform and really care about bundle size, it can be a good choice. But at that point, I do wonder if you should just bite the bullet and write a native app.
|
||||
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: "Why I migrated from Tauri to Electron"
|
||||
description: "Why I migrated from Tauri to Electron after rendering, WebKitGTK, notifications, and bundling a Node daemon made the pragmatic choice obvious."
|
||||
date: "2026-03-29"
|
||||
draft: "true"
|
||||
---
|
||||
|
||||
I picked Tauri because it felt like the smarter choice.
|
||||
|
||||
Smaller runtime, lighter footprint, better story on paper. Electron felt brute-force by comparison. I remember having that feeling of "yeah, I'm not going to ship a whole browser just to build a desktop app."
|
||||
|
||||
Then I had to ship a real app.
|
||||
|
||||
Not a toy wrapper. A real cross-platform app with stable rendering requirements, a bundled Node daemon, and Linux support.
|
||||
|
||||
That's when my opinion started changing.
|
||||
|
||||
The first big crack was rendering stability. When you're building something you actually want people to use daily, that matters a lot more than the abstract elegance of the stack. I started caring less about theoretical efficiency and more about whether the UI behaved consistently across machines.
|
||||
|
||||
Then came the daemon side.
|
||||
|
||||
My app bundles a Node daemon. I spent a long time making that work inside Tauri. And to be fair, I did get it working. But at some point I had this pretty uncomfortable realization:
|
||||
|
||||
I was basically reinventing Electron.
|
||||
|
||||
I had picked Tauri partly to avoid bundling that whole world, and then product reality pushed me into rebuilding pieces of it anyway. What had started as architectural elegance was turning into self-inflicted complexity.
|
||||
|
||||
Then WebKitGTK really pushed it over the edge.
|
||||
|
||||
If you care about Linux, WebKitGTK is not some small implementation detail you can ignore. It becomes part of your product. Its bugs become your bugs. Its rendering behavior becomes your rendering behavior.
|
||||
|
||||
The WebKitGTK version Tauri picked up by default was old. Wayland did not work at all. After forcing a specific newer version of WebKitGTK and getting things to actually run, the rendering was all over the place. Worse than Safari, which already had its own set of platform-specific bugs I was chasing.
|
||||
|
||||
So I had Safari bugs on macOS, a broken or outdated WebKit on Linux, and Wayland not working. Suddenly the "lean" choice did not feel lean anymore.
|
||||
|
||||
I even got to the point where I was thinking: if I keep going down this road, I'm going to end up embedding my own renderer anyway.
|
||||
|
||||
That was the moment where the whole thing collapsed for me.
|
||||
|
||||
Because what exactly was I optimizing for anymore?
|
||||
|
||||
But the thing that probably burned me the most was notifications.
|
||||
|
||||
In my app, notifications are not a nice-to-have. Users need to click a notification and get taken to the right context. Pretty basic stuff.
|
||||
|
||||
Tauri could not handle notification click actions on desktop. You could show a notification, but you could not attach a callback to route the user somewhere when they clicked it. They did implement this for mobile, which honestly made me start to wonder where their focus actually was.
|
||||
|
||||
I ended up building platform-specific hacks to get click handling working across macOS and Linux. At that point the benefits of using Tauri were mostly gone. I was writing the glue code myself anyway.
|
||||
|
||||
In Electron, this was attaching a callback. That's it.
|
||||
|
||||
Electron started looking different after that.
|
||||
|
||||
Less "bloated default" and more "boring, stable, pragmatic runtime with fewer platform-specific surprises."
|
||||
|
||||
I changed my mind about it.
|
||||
|
||||
I still think Tauri is appealing. I get why people choose it. I chose it for the same reasons. And if your app is simple enough, or your platform constraints are different, maybe it's still the right call.
|
||||
|
||||
But for me, once the app got real, Electron became the more honest choice.
|
||||
|
||||
The lesson I took from this is pretty simple:
|
||||
|
||||
Sometimes the "smart" technical choice is only smart in the phase where your product is still hypothetical.
|
||||
|
||||
Once you have real requirements, real users, rendering issues, packaging issues, and platform-specific weirdness, the less elegant tool can end up being the more pragmatic one.
|
||||
|
||||
If you've gone the other direction, I'd be curious what your app looked like and where Tauri held up better.
|
||||
Reference in New Issue
Block a user