Building the Debug Trainer Deskop App with Tauri

debug-trainertauri

Cross-posted from the official Kickstart Coding blog

I posted recently about the release of the desktop version of our Debug Trainer debugging practice app.

Today I thought I’d talk a bit about a tool we used to write that desktop application using mostly front-end languages and tools: Tauri.

The Tauri homepage, with the Tauri logo and the tagline “Build smaller, faster, and more secure desktop applications with a web frontend”

If you’ve used Electron to build desktop apps before, Tauri is similar. Both Electron and Tauri make it possible to use front-end languages like HTML, CSS, and JavaScript to build desktop apps. Basically, you build a web site with HTML, CSS, and JavaScript, but then you can run it in its own app window and make it do desktop-app things like read and write files, send notifications, etc.

Electron accomplishes this by incorporating Google Chrome’s HTML rendering engine into a desktop application and providing a specialized node-based back-end. Tauri does this by using each operating system’s built-in HTML rendering toolkit (aka “WebView”) and providing a specialized Rust-based back-end. Electron’s way makes for larger, more memory-hungry, and less secure applications compared to Tauri. Tauri’s approach makes for smaller, lighter, and more secure apps at the cost of having to think a bit more about browser compatibility since different operating systems use different HTML rendering engines.

Having used Electron in the past and experienced a fair amount of frustration getting things working and built, I decided this time around to give Tauri a shot instead.

Setting Up Tauri

Tauri is VERY open-ended about your front-end setup. As long as everything ultimately compiles to an HTML file, you can use whatever front-end framework or bundler you want. I opted to use mostly Elm for my front-end, both because I love it and because I had also used Elm for the CLI version of Debug Trainer. A bit of TypeScript was also needed because some more JavaScript-ish code is required to use the back-end interop features.

In the end, I had a bunch of Elm files for the user interface and an app.ts file for connecting the UI interactions to functionality like choosing files, reading files, writing to files, and exiting the app. I used elm-live to compile the Elm code, and Parcel.js to combine the compiled Elm with the app.ts file and put it all in a dist folder.

Normally you wouldn’t need elm-live in this setup at all, but the Parcel v2 beta is having some issues with Elm at the moment.

With that all setup, the rest is just installing the Tauri-specific part of the setup.

  1. installing the Tauri CLI
npm install -D @tauri-apps/cli
  1. adding a tauri script to your package.json file
  "scripts": {
    "tauri": "tauri"
  }
  1. running the init command
npm run tauri init

This adds all of the Tauri essential files and folders. If any of the above doesn’t work for you, here’s the docs page that should have the latest.

Building Stuff

I don’t know Rust at all, but it turns out if your app isn’t too complicated, you don’t really need to. Basic app settings like width, height, app icon, etc are all just specified in a tauri.conf.json file, and most basic bits of functionality are provided via JavaScript functions in the @tauri-apps/api library. Once you’ve installed that, access to file reading/writing functions is just importing them like this

import { readTextFile, writeFile } from '@tauri-apps/api/fs'

and the function to call to exit the program can be imported like this

import { exit } from '@tauri-apps/api/process'

You can read about the rest of the API for various bits of functionality in the Tauri API docs here.

Beyond figuring out those imports, the rest was just regular old front-end app programming. Build, compile, test, commit, build more. I was frustrated that I couldn’t seem to get the tauri dev command, which runs a development version of the Tauri app you’re building, to do any live-reloading of code changes like you can get in the browser. In fact, sometimes even when I exited the tauri dev process entirely and recompiled it from scratch (or so I thought), it still seemed to take it a couple of stop/restart cycles to reflect new code changes. Because most of my changes didn’t use the Tauri-specific features, I dealt with this by editing via the Parcel.js server directly in my browser when I could. For a more feature-heavy app, though, I could see this being a serious stumbling block.

Building the Desktop Apps

Once I had the app working in development mode, it was time to figure out how to build an actually working application package that other people could download and use. The tauri build command took care of building a Mac version on my Mac, but since I didn’t have an easily available Linux or Windows machine to do a build for those operating systems, I ended up getting acquainted with GitHub actions in order to take advantage of the Tauri Cross-Platform Compilation GitHub action.

I mostly try to avoid using GitHub where possible on account of their contract with ICE and long history of sexism, intimidation, and other issues, so I hadn’t had any particular reason to learn about GitHub actions before now. But in this case, with no viable alternative, I decided to dive in.

It took me a lot of reading to get a sense of what GitHub actions are and how they’re supposed to work — what the differences were between workflows, jobs, steps, runners, etc. But eventually I figured it out, and after a bit of tinkering and debugging I created a slightly modified publish workflow that can build apps for all three operating systems successfully. Getting it built it was challenge, but now that it’s finished, running it is nicely straightforward.

I was also shocked and impressed to discover how small the final app was (12mb for the Mac version!).

the Debug Trainer app icon with a size of 12.1 megabytes listed below it

Community Help

The few times I did hit snags with Tauri, I found the Tauri Discord community to be incredibly helpful. Very quick responses, useful advice, and no condescension when my very first question was “I’m pretty sure my app is on the latest version but I can’t get the Tauri JavaScript tools to work at all” and the answer turned out to be “Your app is not actually on the latest version” 😅.

All in All

With the exception of the reloading issues in development, I’d say that my experience using Tauri was pretty good. Definitely nicer than the last time I tried to build something with Electron, although in Electron’s defense that was probably five years ago and they may have improved things since then. I like the straightforwardness of the JavaScript APIs and the general setup. I love how easy it is to build cross platform versions of the app — this is one thing I specifically remember being much harder with Electron. I will definitely be defaulting to Tauri if/when I decide to try building more desktop applications in the future.