DEV Community

Cover image for Electron to Tauri: A 24-Hour Rewrite with Claude ๐Ÿš€
Ankur K
Ankur K

Posted on Edited on

Electron to Tauri: A 24-Hour Rewrite with Claude ๐Ÿš€

Google Chat for your desktop โ€” tray icon, desktop notifications, native window, built with Tauri

TL;DR ๐Ÿ“Œ

  • ๐Ÿ•ฐ๏ธ Then: I built google-chat-electron by hand, over months, reading tutorial after tutorial.
  • โšก Now: I rebuilt the whole thing as google-chat-tauri in less than 24 hours โ€” and I did not write the code. Claude did.
  • ๐Ÿฆ€ Plot twist: I don't know Rust. Not a little โ€” at all. The AI wrote every line of it.
  • ๐Ÿ“ฆ Result: a 3.3 MB Linux installer, against 66 MB for the Electron build of the same app. Same features. Real numbers, measured off both repos' release assets.
  • โœ… Status: v1.0.1 โ€” stable. Six releases in, and the pre-release label is off.

Let's dive in. ๐Ÿ‘‡


The Electron Era: Months of Honest, Manual Labour ๐Ÿ˜…

A few years ago I wanted Google Chat in a real window โ€” with a tray icon, an unread badge and native notifications โ€” instead of a browser tab that disappears among thirty other browser tabs.

So I built it. In Electron. By hand.

And it took months. Not because Electron is bad, but because every single thing was a tutorial:

  • How do I make a tray icon that actually behaves?
  • How do I keep the app alive when the window closes?
  • How do I intercept a link and open it in the real browser?
  • How do I package a .deb? A .dmg? An installer for Windows?
  • Why does this work on my machine and nowhere else? ๐Ÿ™ƒ

Every answer was a blog post, a GitHub issue thread, or a Stack Overflow reply from 2017 that almost applied. It shipped, people used it, and I was genuinely proud of it. It's no longer maintained โ€” this is its replacement.

The Tauri Rewrite: One Evening, One Prompt Loop ๐Ÿค–

I opened Claude Code and asked it to port the app to Tauri v2.

I did not open the Rust book. I did not read the Tauri docs. I described what the app should do, reviewed what came back, ran it on my actual laptop, and reported what broke.

Timeline:

Time What happened
15:42 git init
17:01 Full Electron โ†’ Tauri v2 port committed
17:25 Desktop notifications working
< 24h later v0.0.1 tagged and released ๐ŸŽ‰
+2 days v1.0.0, then v1.0.1 โ€” stable โœ…

72 commits. ~5,100 lines of Rust and JavaScript. Zero lines typed by me.

This is what people mean by vibe coding โ€” and honestly, it felt less like programming and more like directing. My job became: describe the behaviour, test it on real hardware, and say "the tray icon doesn't come back on Wayland." The AI handled the rest.

โš ๏ธ The honest caveat: AI wrote it, but a human ran it. Almost every real bug was a platform behaving differently from its own documentation โ€” the kind of thing no model can find by reading docs. That part still needs a person with a laptop and some patience.


Tauri vs Electron: Why the Rewrite Was Worth It โš–๏ธ

Here's the thing โ€” Electron ships an entire Chromium browser with your app. Tauri doesn't. It uses the web engine your operating system already has: WebKitGTK on Linux, WKWebView on macOS, WebView2 on Windows.

โš›๏ธ Electron ๐Ÿฆ€ Tauri v2
Browser engine Ships its own Chromium Uses the OS web engine
Linux installer size 66 MB (my old app) 3.3 MB (the same app) ๐Ÿคฏ
Backend language Node.js Rust
Memory footprint Heavy โ€” it's a browser Noticeably lighter
Startup Boot a Chromium Boot a native window
Security model Opt-in hardening Capability-based by default

Those two size numbers are the same app, same features, measured off the release assets of both repos. 20ร— smaller. ๐Ÿค

The rest of the bundles land in the same place: 1.9 MB for the Windows installer, 6.0 MB for the universal macOS .dmg. The one outlier is the Linux .AppImage at 85.7 MB โ€” and it's the exception that proves the rule, because it's big precisely because it carries its own copy of the web engine for distributions that can't supply one.

The size difference is the headline, but the one you feel every day is startup and memory. You're not launching a second Chrome just to read messages from your team. The window opens like a native window, because it basically is one.

The trade-off? You inherit the OS web engine's quirks โ€” and they are real. WebKitGTK renders its failed-load page as literally <html><body>%s</body></html> with no styling whatsoever, which on a dark window means black text on a black background. Chromium would never. More on that below. ๐Ÿงช


What the App Actually Does โœจ

This isn't a "hello world in a webview." It's a real desktop client:

  • ๐Ÿ”ด Unread indicator โ€” a dot on the tray icon, the count in the window title, and a badge on the macOS dock or Windows taskbar.
  • ๐Ÿ”” Desktop notifications โ€” with sound. On Linux, clicking one brings the window back.
  • ๐Ÿ—‚๏ธ Lives in the tray โ€” closing the window hides it; the app keeps running and keeps notifying.
  • ๐ŸชŸ Remembers your window โ€” size, position and maximised state come back where you left them.
  • 1๏ธโƒฃ Single instance โ€” launching again just focuses the window you already have.
  • ๐Ÿ“‹ Native menu bar โ€” File, Edit, View, History, Preferences, Help, with zoom that persists between launches.
  • ๐Ÿš€ Starts how you like โ€” launch at login, and/or start hidden in the tray on any launch.
  • โŒจ๏ธ Keyboard shortcuts โ€” Ctrl+F to search, Ctrl +/-/0 to zoom, Alt+โ†/Alt+โ†’ to navigate, Alt+Home to get back to Chat, Ctrl+W to hide to tray.
  • ๐ŸŒ Links open in your real browser โ€” a Docs, Sheets or Calendar link opens where your extensions and logins already live. Only Chat stays in the window.
  • ๐Ÿ“Ž Attachments download through your browser โ€” it saves them the way it saves anything else.
  • ๐Ÿ” Signs in normally โ€” personal Google accounts and paid Workspace accounts, in any country.
  • ๐Ÿข SSO sign-in works too โ€” Okta, Entra ID, Ping and friends.
  • ๐Ÿ“ก Handles a missing network gracefully โ€” a readable offline page with a Try again button, and it reconnects on its own.
  • ๐Ÿงฏ A way back from a wedged session โ€” Help โ†’ Reset App Data signs you out, resets every preference and restarts clean.
  • ๐Ÿ•ต๏ธ Logs you can paste into a public issue โ€” paths and URLs go through a redactor first, so nothing in them names you.

No analytics. No auto-updater installing things behind your back โ€” it just asks GitHub once or twice a day whether a newer release exists and tells you. You can turn that off. ๐Ÿ™Œ

Available for Linux (.deb + .AppImage), macOS (universal .dmg) and Windows (.exe).


The Bugs Reality Found ๐Ÿ›

This is the part I'd actually read if someone else wrote this post. Every one of these was found by running the thing, not by reading docs โ€” and every one of them is a platform doing something other than what it documents.

๐Ÿข SSO / identity-provider sign-in

If your company signs you in through Okta, Entra ID or Ping, the flow redirects to your organisation's host โ€” which the app can't know ahead of time, so it isn't on the short list of hosts allowed to stay in the window. The link opens in your browser and finishes the sign-in there, leaving the app still signed out. ๐Ÿคฆ

The fix is pleasingly simple: Preferences โ†’ Temporarily Open Every Link in This Window. It explains what it's doing before it does anything, keeps every link inside the app for five minutes โ€” long enough to get through any SSO flow โ€” and then switches itself off again. No permanent footgun left enabled.

๐Ÿšช Sign Out that doesn't strand you

After signing out, Google sometimes answers a session-less visit with workspace.google.com โ€” a marketing page โ€” instead of the login form. And that page's own "Sign in" link did nothing, because the injected script intercepts cross-origin clicks on every page, the IPC permission only covered Google's Chat and Mail domains, and the resulting rejection was silently swallowed. Click โ†’ cancelled โ†’ dropped into the void. ๐Ÿ•ณ๏ธ

Now the window navigates itself when Rust can't be asked, and the app redirects off that marketing page to the real sign-in form (at most twice โ€” a redirect loop is worse than a dead end). You should never have to wipe your data to sign back in.

๐Ÿ“ก An offline screen you can actually read

Remember that WebKitGTK failed-load page? Black text, dark background, one unstyled line. The app rewrites that document into something readable with a Try again button.

Which, delightfully, could not simply reload โ€” WebKit refuses to navigate its error page to the URL it's standing in for, and the page's opaque origin makes every IPC call fail with Origin header is not a valid URL. So the button aims at Chat's canonical URL instead, and in the background the app keeps probing the network and loads Chat by itself within about half a minute of your connection coming back. Usually before you even reach for the button. โœจ

โŒจ๏ธ Keyboard shortcuts that were pure decoration

Alt+Home was declared on the History menu and answered by absolutely nothing โ€” GTK accelerators never reach the app while focus is inside the webview. Fine, route it through the injected script like every other shortcut.

Then Windows turned out to be worse. Tauri does build the accelerator table, and Windows does draw Ctrl+W next to the menu item โ€” but the hook that would dispatch it only sees messages that reach the window's own message loop, and WebView2 has focus, always. Measured with synthetic keystrokes: Ctrl+W does nothing, clicking the exact same menu item works fine. The app now asks WebView2 for those keys directly. ๐ŸชŸ

๐ŸงŠ A notification that froze the window

Showing a desktop notification on Linux measured, over 25 calls: median 48 ms, p90 86 ms, max 520 ms. Tauri runs synchronous commands on the main thread โ€” which, on Wayland, is also the thread drawing your window's own close and minimise buttons. So a notification arriving made the titlebar stop responding, which reads as "the buttons are broken", not "the app is busy". Notifications now go out on a long-lived worker thread. ๐Ÿงต

๐Ÿคฆ The bug I find funniest

The update checker couldn't see pre-releases. Which is a genuinely hilarious flaw in an app whose only releases were pre-releases. v0.0.1 could never have told you v0.0.2 existed.

The punchline is that GitHub's /releases/latest 404s for a repo that has only ever pre-released โ€” it's documented as "the most recent non-prerelease release", so with nothing but pre-releases there is no latest at all, and the 404 is indistinguishable from having never shipped anything. Now that 1.0.0 is out, the rule flipped again: only stable releases are ever offered, so a beta never gets pushed at anyone. ๐Ÿ”

๐Ÿ”’ Plus the boring-but-important stuff

  • Logs stopped leaking identity. Every path starts at your home directory, Google puts your email in sign-in URLs, an attachment link carries a bearer token, and a Chat URL's fragment names the open conversation. These files exist to be attached to public GitHub issues, so paths and URLs now go through a redactor on the way in.
  • The injected script got smaller off Chat. The full script only runs on Chat's own origin now; everywhere else gets the bare minimum it needs to hand a link to your browser.
  • CI got teeth. Five checks โ€” fmt, clippy, cargo test, a syntax check and the injected script run against a stand-in page โ€” gate the release workflow, so a tag on a commit that fails any of them produces no artifacts at all.

๐Ÿšซ And one thing that simply cannot be built

Clicking a notification can't open that conversation. Chat's real notifications come through the service worker with no click handler the page can reach; the payload's tag identifies the sender, not the thread; and the document URL never moves off /app/home as you walk between conversations โ€” confirmed in a stock browser, so it isn't a webview artefact. A click raises the window and stops there. Sometimes the answer is "no", and writing down why is worth more than another attempt. ๐Ÿคท


Where Things Stand โœ…

Let me be very clear about this part:

  • ๐ŸŽˆ This is a fun project. It scratches an itch. It is not a startup.
  • ๐Ÿฆ€ I don't know Rust. If you open an issue about a borrow checker decision, the AI made it, not me.
  • โœ… It's stable now. v1.0.1. Linux needs glibc 2.39+ (Ubuntu 24.04, Mint 22, Debian 13 and newer), macOS 15 Sequoia and newer, Windows 10 (1803+) or 11.
  • ๐Ÿงช Linux is where it's been tested most. The macOS and Windows builds exist, CI produces them, and they still want real users on real machines. Both are unsigned, so the first launch needs a click through Gatekeeper or SmartScreen โ€” the README spells out exactly which buttons.

If you use Google Chat on the desktop, try it and tell me what breaks. Every fix in the section above exists because something broke in real life โ€” that's genuinely the most useful thing you can contribute. ๐Ÿ›

# Debian, Ubuntu, Linux Mint
sudo apt install ./google-chat-tauri_*_linux-amd64.deb
Enter fullscreen mode Exit fullscreen mode

(The leading ./ matters โ€” without a path, apt goes looking for a package by that name in your repositories.)


The Takeaway ๐Ÿ’ญ

Months of manual work, then a full rewrite in a different language, on a different framework, in under a day โ€” by someone who can't write that language. Stable a few days later.

That's not a flex about me. It's a data point about where tooling is in 2026. And the releases since make the shape of it clearer: the hard part was never typing the code. It was knowing what the app should do and checking it against reality โ€” the WebKit error page, the Google marketing redirect, the GTK accelerator that goes nowhere, the notification that freezes a titlebar. AI took the first job, instantly. The second one is still ours. ๐Ÿค

Every one of those findings is written down in the repo โ€” what was measured, and on what โ€” next to a file explaining which bits of code look wrong until you know why. That documentation isn't ceremony. It's the only thing stopping the next change from quietly undoing a fix that cost an afternoon. ๐Ÿ“š


๐Ÿ”— Links


Unofficial app. Not affiliated with, endorsed by, or sponsored by Google. "Google Chat" and the Chat logo are trademarks of Google LLC.

Have you migrated an Electron app to Tauri? Or vibe-coded something bigger than you expected? Drop it in the comments โ€” I'd love to read about it. ๐Ÿ‘‡

Top comments (1)

Collapse
 
devops_descent profile image
DevOps Descent •

wow๐Ÿง,need to try it out