JS Party – Episode #265
Tauri brings Rust to the JS Party
with Daniel Thompson
KBall and Nick interview one of the leaders of the Tauri project about this next generation app bundling toolkit: the security, size, and performance features that make it special (and dare we say, better than Electron?), and what’s coming next.
Sentry – Session Replay! Rewind and replay every step of the user’s journey before and after they encountered an issue. Eliminate the guesswork and get to the root cause of an issue, faster. Use the code
CHANGELOG and get the team plan free for three months.
KBall Coaching – Free exploratory coaching sessions from JS Party co-host KBall! Click here to get started
Notes & Links
|3||02:17||It's party time, y'all|
|5||07:57||Bringing Rust to a JS Party|
|6||10:34||If you've never worked in Rust before|
|7||13:13||Rust + TypeScript|
|8||19:57||Sponsor: KBall Coaching|
|9||21:13||What makes Tauri special|
|15||49:47||Cool Tauri apps|
|16||52:13||What's coming next|
Click here to listen along while you enjoy the transcript. 🎧
Hello, JS Party people. Welcome to another wonderful episode of your party on the web, JS Party. I’m Kball, I’m your host this week. I am joined, first off, by one of my most common co-panelists, the one, the only, Nick Nisi.
Hoy-hoy! How’s it going?
It’s going well. And then we have today a special guest, Daniel Thompson from the Tauri Project. Daniel, welcome to the show.
Hey, thanks for having me. It’s great to be here. I’ve been partying with JS forever, it seems like.
Absolutely. Well, let’s start with you, Daniel. So can you tell us a little bit about that partying with JS forever? Give us your backstory. How did you get to where you are today, and what is it that you’re working on?
And in the course of one of those projects, I realized that the ecosystem for hardware and the ecosystem for software just wasn’t really serving the creative community. And around that time I met the co-founder of Tauri, Lucas… And at the moment, I think – back then we were struggling with getting apps on the app store for PureOS. And for various reasons, the stack that was being proposed wasn’t appropriate, and Lucas and I went shopping around, and we found WebViews. And we’re like “How come nobody told us about WebViews before?” He was React, and I was Vue, and all of a sudden, there’s this way to make basically a PWA, but with superpowers. And that kind of led to this four-year experience of building an open source project, creating a community, staying responsible, and… I don’t know, it’s been great to see this group grow like a piece of software, like an iterative growth, where no idea is just thrown out because we don’t know how to do it. If we don’t know how to do it - well, we’re engineers; that’s what we do, we figure these kinds of things out.
So we have examples for almost all of the features in our Tauri repo, and the lower, deeper tech libraries, where you can see how the features are actually used. And we even have a verification app that we build to smoke-test to make sure that changes to the code don’t break the apps. And I have to tell you, copy paste is the programmer’s keyboard. Ctrl+C, Ctrl+V… And that’s how I learned to program. I didn’t have formal education as a software engineer. And I know Lucas is smiling, like “Yes, Daniel, we know; we can see in your code.” [laughs] But what you learn as an engineer, the challenges you face, you have to solve them, and you know that somebody else probably had the same problem, and then you can find that… And what we’re trying to do with our examples, and what every Rust project does, or should do, is provide examples for people to see how it’s actually being used… And then please, copy our homework, right? That’s how this open source thing whole all works.
Yeah, I think that feeds into – there’s like this common misconception that you should start from the top-down explanation, and people will be able to immediately see all the implications. But mostly, we learn better by a lot of examples, and then working up to the general principles.
I mean, if you’ve never worked in Rust before, let me just break it down for you. So generally speaking, you have libraries that you can import, and you can call that functionality. And you have – it’s kind of like an execution loop. So basically, once you’ve entered that loop, it’ll keep on looping until you get some reason to stop it. You end the program, or there’s a failure… And I’ve gotta tell you, in Rust you fail a lot. Like, it’s something you get used to. But that’s because we are compiling the language down into something like a binary; it’s machine code, it’s very small… It’s not interpreted at runtime.
So the Rust compiler is written by just some of the most amazing engineers I’ve ever had the pleasure of talking to. I wish I would be able to understand everything they say… But when you make a mistake, the compiler is like “Hey, this is probably wrong. You don’t mean to have a string here; it’s a different type.” It’s a common, common example of one of the various problems you can run into in a very strictly typed programming language. It’s, in a sense, more strict than TypeScript. It’s very, very, very, very strict. You have to get it right. And if you don’t get it right, it’s not going to build.
I’d be interested to explore a couple pieces of that… I mean, one thing that I know from my very limited experience with Rust is, unlike with TypeScript, it actually gives you useful error messages when there are problems in the compilation step. I mean, TypeScript can, occasionally, but it’s pretty rare, right? I think most of the time TypeScript does an error, and you’re like “Shoot. What do I need to do to figure out this error?” “These types don’t match.” “Why not? They should…” Whereas Rust’s compiler will say, “Oh, this thing isn’t right. Maybe you meant to do this instead.”
“Check out error message e462…” It’s sometimes helpful, it’s also daunting. And I think that one place where the Rust community can do a better job - and I’m looking at the compiler crew right now - is making it less scary. Like ELI5 it for me, please… Because what you have to understand - the development of the Rust programming languages has evolved and been forced by extraordinarily intelligent people who’ve been following along in the whole conversation. And for beginners sometimes it feels like somebody just brought you into a Discord chat that’s been going on for six years, and you don’t even know – like, what are you talking about here? And I think that it is something actively being worked on, to make that helpful compiler message even more friendly. So it’s on the track to getting better, I know it.
One of the things that we’re revising internally is the fact that your experience using the Tauri interface - and this is where it gets a little bit nerdy for Tauri users, so I’ll try to keep it on a higher level… But when you create a command that allows you to interface with the Rust, you’re going to be doing that in TypeScript. And how do you know for a fact that the types are the same on both sides, if you’re only passing messages? So there’s a couple of approaches that we’re working on, that will actually provide those types from Rust… So that as long as the Rust compiles, your TypeScript is going to be fine, and you’re going to be able to talk with the same types across the boundaries.
[00:15:55.00] For me, what that ultimately means is that, you know, when we’re talking about structured data, we know on both sides what we’re talking about. In a sense, it’s the best parts of convention and configuration, right? So you’re able to configure it, but you have this convention that’s going to keep it going from the source of truth, and I feel like the strongest types available in a Tauri app are gonna be coming from Rust. And in the user interface, you want to have access to those types. You don’t want to be messing around, like, yeah, you’ve got a user profile with ID, and that’s an integer, and a password, and that’s an obfuscated, encrypted string… And then Tauri doesn’t care how you pass your bytes around. Like, yeah, you have to serialize, you have to deserialize; that’s the nature of the beast. But when you talk about developer experience - and I think that’s what TypeScript really brought to our ecosystem, is think about your types, make sure that they fit, and find the truth, and stick with it. Right?
So am I hearing you correctly that you’re actually generating the TypeScript types from Rust, similar to how you might get TypeScript types generated from a GraphQL integration, or…?
There are ways to do this. There’s a project from a group… I don’t know if you’ve heard of Spacedrive before; they’re building an app to collate all of your remote drives. And they built an amazing project because they were facing this problem themselves. And we had a solution that we were working on internally, but these guys are so excited about Tauri that they just joined our working group; they joined the open source working group, and right now we’re discussing how to effectively place this type definition manufacturing system into the core… Or is it going to be a plugin…? Because, I mean, really, in 2023 who starts a project without TypeScript? There’s nuances there to deal with, but it’s really important to us that you have this unified development experience. Because once you start building a greenfield project with the Tauri ecosystem, you’re going to use the TypeScript frontend, but you’re also going to leverage the power of the Rust core. And if you need to switch your mental model from one to the other because you are not strictly managing your types across this boundary… In a sense, it’s also why people love GraphQL. You have the same mental model everywhere, and that reduces the cognitive load when you’re switching between these contexts. And for bigger projects, between teams, right? Maybe you just have a frontend team, and you have a backend team, and you have a DB team, and you have the ops team, and you have the QA team, and you have the management team, and all these teams need to talk the same thing… And from that meta perspective, I think that agreeing on what it is we’re talking about has to be done in a strict way. Otherwise, you’re doomed as an organization and as a project. That’s organizational debt right there.
So let’s roll back in and talk about what makes Tauri special to a user. We’ve spent a lot of time talking about what is Tauri, some of the fundamentals, some of the principles even that you’re following there in thinking about it… But if I’m deciding on a toolkit to use, because I want to build a desktop application, what are the things that Tauri has focused on that make it unique and what I should choose?
Well, you used an interesting word, and I’m gonna start being strict about words, because I think they’re important. You said user. And my first reaction was, “Oh, the user of a Tauri app is the person who downloads it and installs it on their computer.” But then I realized that you meant the user of the framework, which is also a very valid user persona. However, I think for both of these personas what I’m about to say is going to align very well… And that is, first and foremost, the size.
So a classical Tauri app these days weighs in at about six megabytes. If you’re using something like Svelte, it might be a little bit smaller; React, maybe about that. You can be careful about how you bundle in your images, and there’s ways to get down to three megabytes. I think Jonas from the working group was able to make a 500-kilobyte macOS app bundle… So the size is relevant. And without going too far into this spoiler, I think it’s actually where we are in the 2020s, right? Like, the 2010s were all about “Thank goodness it works. I built something that works. I don’t care how I got here, but it works.” And that whole free real estate mentality has led to engineering paradigms where on every data frame you send an entire object across the wire, instead of sending a diff, for example, when something changes. Like, I got it to work, so whatever; I don’t care about the consequences. And, I mean, we can be honest with ourselves - a hobby application that 1,000 people use doesn’t have that much impact. But a VS Code that is used by tens and hundreds of millions of people around the world on a daily basis, that weighs in at 600 megabytes, and every download, every update that they ship every two weeks is another 600 megabytes, that is a massive amount of traffic. And yes, if you’re in a place where you have a good fiber uplink, you don’t notice it. Right? You just kind of suck it. And your hard drive just kind of is like “Okay, I still have enough space”, so I don’t have to delete those photos, or I’ll keep those videos around. It’s still just 600 megabytes, right?
[00:24:02.07] I was in Istanbul about five weeks ago… And I have two cell phones. I have a work cell phone, a mobile phone, and a personal one. One of them is a French mobile phone, and the other one is a Maltese mobile phone. And one of them wanted me to pay 10 cents per megabyte of transfer. Did I have any other Wi-Fi access? Not one I trusted. Could I update VS Code? That adds up, right? And I think this notion of “Hey, who cares? It’s just traffic” is blatantly wrong. And I could go on for hours about how even reducing the package bundle size is a positive step in the right direction for protecting our environment… But I think the next most important part of Tauri apps is the security features that we offer as a framework.
Now, as you know, Rust is a language that is strict with its memory management, which provides a number of memory guarantees… But Rust isn’t a panacea. I think that’s something that people who are new to the Rust community ecosystem, listening right now for the first time hearing about Rust, need to get through their heads. Just because Rust is better doesn’t make it a silver bullet. You can still write bad, insecure code in any language that exists. Just because it compiles doesn’t mean it’s great yet. It’s a good start, but it’s not perfect. And we’ve done our best on multiple layers to provide security guarantees. In addition to things like code signing, which everybody has to do for Mac and Windows apps, we force the developer to add a private key that then is used to sign the bundle, so that the application knows when an update comes that it is actually a valid update. So we don’t just trust the ecosystem, and I think that’s something that hopefully comes through here. We don’t even trust the device, right? So if you as a developer don’t need access to the file system, then you just compile it out of the bundle, right?
So we use this tree-shaking feature that modern ECMAScript allows you to do when you’re importing or requiring a subset of the exported functionality from a library; we do the same thing for Tauri core. So the idea of feature-based compilation becomes really exciting, because you don’t need all of the code for every single platform. And I think when you have an environment that is interpreting what it gets fed, it has to be multipurpose. It has to be able to do everything at any time, because it never knows what it’s going to get. Whereas in our context, if you just need filesystem access and you want to drop into a shell, or run a command, then those are the features and functionality that gets baked into your app, and nothing else. So we’re removing surface area, which reduces gadget attacks.
Can I jump in really quick here? So when you talked about that, and the tree-shaking and cutting things out, my mind, being more of a web developer, immediately went to supply chain attacks, right? I’m including a package, I know that I don’t want it to use the file system, so I’m gonna say there’s no file system in this, and if it tries to use a file system, that’s not my problem, in a lot of ways. But you’re talking about something very different, and my headspace is not usually thinking about devices. But you said, and I saw it on the website - the fundamental here is this concept of the device should not be trusted, right? It’s not like a browser, where we can assume it has some things, it doesn’t have some things controlling it, we control our security, we keep certain things on the server.. Like, all of this is going to the user’s device. So what does a malicious device impact on an application even mean? ELI5 it to me, the web developer who doesn’t deal with devices.
[00:28:11.22] You do deal with devices, they’re just abstracted away from you and you’re not allowed to touch them.
I like that. But those pieces that your tree-shaking out… Like, the way that I’m picturing this - and you can tell me that I’m completely wrong - is like there’s that code that’s probably written in Rust, there’s my code, and then there’s effectively a browser to run my code in. Wouldn’t all of that pale in comparison to the size of the browser that you’re shipping with it, or the WebView piece of that?
We’re using the system WebView.
So on Windows it’s WebView 2, on Mac it’s WKWebView, and on Linux it’s WebKitGTK.
Oh. So it doesn’t have to ship – I’m thinking in terms of like having to ship like a Chromium version. I know it’s not Chromium, but… Okay, it’s just using what’s natively there.
Well, I’m gonna be totally direct and honest with you, that does also bring challenges with it, right? So on macOS, basically, if you’re not using stupid arcane hacks, you’re stuck with the version of Safari WebKit that your version of the operating system runs. And the only official way to deal with that is to update your operating system.
It’s a trade-off, and I think the general win is that we felt you have a greater chance of keeping your operating system up to date for Mac, than updating the thousand apps you’re going to be running. And Windows - Windows actually does a pretty good job of keeping the WebView 2 up to date. So in that context, we’re leveraging the platform ecosystem.
[00:32:09.02] So I guess that’s the final security feature, is our approach to security, and that is we audit internally, but we also audit externally. So Tauri had, I think for 1.0, over 50 findings from the external security team that we resolved… And one of them, the hardest one, the trickiest one is “How do you protect this message boundary between the WebView and the Rust?” And as a response to that, we developed a mechanism that passed the audit, that does exactly that through a protected iFrame.
So is that like using postMessage or something, to do that communication through it, or…? I’m thinking in my simple web developer brain here…
Well, the problem is the parent frame can never really know what its children are doing… And the children shouldn’t have access to the parent.
I’m curious, too… Are you signing something across it? Like, you bundle some sort of key when you do the bundle, or some sort of encrypt/decrypt type thing, or…?
So I’m just gonna read to you from Chip’s post about it… Oh, we’ve just revised the search on the site, so I can’t find anything anymore… Can we circle back to this?
Oh, absolutely. What we’ll do is we’ll put the details in the show notes. So send us a link after the show, and we’ll put it there. Anyone who’s curious – I know I’ll be going and reading through, because I’m curious to dig into exactly how you do it is.
I mean, it is using postMessage, and the key for the encryption of the message is injected from Rust… But the details are quite long.
Alright. So you were about to tell us about performance.
Right. And this is actually one of those weird situations where I think different platforms have different interpretations of what performance means. So the Windows platform tends to be the one that people analyze the most, and think that the memory overhead is the big issue, right? And so depending on how you analyze it, some people say that Tauri only has a little bit less memory needs than for example Electron… But the interesting part about WebView 2 on Windows is that the shared nature of it reduces the overall memory load. Whereas if you’re running 10 - I’ll just name them, the 10 Electron-based apps - you’re not sharing any memory, because they’re all isolates. And what that means is when looked at from the isolated perspective of one app compared to one other app, you’re going to find comparisons that are similar. As soon as you have ten of each, or multiple of each framework running at the same time, you’ll see that the total memory load is lower.
Are you saying that if Slack was built on Tauri instead of Electron, running all the ten different workspaces that I’m in would not use ten times as much memory, the way it seems to now?
[00:36:19.24] And when you start looking at high-performance applications that need to have that data throughput, maybe they don’t need to display everything, but they have to pass that data through in order for the user interface to decide what it shows. I’m not sure other single-threaded runtimes are going to be up to that challenge, right? And so with the clever architecture of separating the concerns between the user interface and the backend core allows you to have as many threads as you need, ultimately. You could be rendering a stream in the backend, and showing the frames in the frontend, and you can also ask for a notification to pop up, and none of it is really blocking, because the entire message boundary is async.
So you really have this world where a message passing is golden, inter-process communication is the way stuff works… But it’s messages. And I think that when it comes to performance - and that’s something that we’re really excited about and working on improving - you have to be strict about what you mean. That comes back to that whole rabbit hole of what are we even really talking about here when we call an app performant - are we talking about having a list of one million elements that you want to be able to scroll through like butter? I’m not even sure that other native frameworks – I mean, maybe Flutter can, with some trickery… But I believe it’s really only rendering the things that need to be on the screen when they are on the screen, which is the right way to do stuff.
So just because your website isn’t rendering in 60 or 120 frames per second doesn’t mean that it can’t; it just means that things need to be rearchitected. And I believe that there are situations in specifically molecular analysis, for example, where you need to have that performance, and you just cannot get it from a browser.
I would absolutely agree with you, and I think what we’re seeing now is close to a paradigm change. I mean, last summer when we released Tauri 1.0 it was the week where both Internet Explorer and Atom Shell’s deprecation was announced. And I think that technology has the ability to stay relevant as long as the people while using it are not afraid to continue developing it. And if you look back to all of the IE11 browser hacks that had to be applied to just even get anything done - and it was like a workaround on top of middleware. And I’m not saying that Internet Explorer was bad, it’s just a piece of technology that served its purpose.
So coming at this from getting started in a web dev perspective, you did mention selecting the right framework for it, and getting started with that. I’m curious, is there something special about the approved frameworks with it that you’re building on top of? Or is that just like a helper, and you could really use anything out there? Does it only work with a certain select set of frameworks?
Unfortunately, it works with every framework. [laughter]
I like that answer.
I love that. So if you want to use jQuery and build your Tauri app, you can.
That’s what I was asking, really…
[00:44:22.01] Vue.js, as you know, freezes after it builds. So basically, we can’t freeze before. So Vue modifies the prototype, because it has to, and while I understand their decision, there’s also that point in time before Vue.js exists that is still dangerous when you’re not in a browser context. Like, Tauri apps can eval anything from the Rust side. So Rust really has that kind of superpower to do anything it wants, at any time.
When you say freezing the prototype, can you clarify what you mean? I’m thinking like object.prototype in my head…
That’s what we’re talking about.
One example of prototype being clobbered - it might be used in console rewrites, for example. And I think it’s less about the fun parts, it’s more about the expected parts and the things you don’t want to happen, right? So if you’re able to attach a new parameter to a const, that is part of the language framework. It’s scary. If you don’t freeze the prototype, you’re doing something wrong. Like, if you’re not freezing your objects after you make them, because they’re never gonna change, you’re forgetting the important stuff, in my opinion.
Speaking of who you want to work with, and who your friends are - if somebody wants to work with you on this open source project, they want to get involved… Maybe they’re a beginner, they may have never done Rust, what have - how can a beginner start getting involved with Tauri, the open source project?
Well, I have always been of this very, very strong opinion that any contribution is a valuable contribution. If you want recognition, make a pull request. Like, there’s your name on it. If you want to help, join the discussion on Twitter and ask hard questions. Or come to our Discord and get informed. Because even asking questions sometimes leads people who are maintainers of the framework to internalize that question, and really think about what they’re building. And the easy win for people to get involved is supporting the documentation effort. Like, with a massive project of this scale, that has so many entrypoints… Sometimes we make a grammatical mistake; I probably made a grammatical mistake just saying that right now.
I think that contributing to open source doesn’t have to be just about the code, it can be about being involved. And what you’ll find if you start contributing to documentation, especially around the API - you have to learn the code. And that means you go into the code, and by reading the code, you become familiar with the code, and the standards, and the way it’s been written, and that will make you a better engineer. Not overnight - this is a long, long, long process - but it will.
[00:48:24.01] And I think ultimately, if you get a taste of Tauri and you like it, I have to tell you, we have a very open working group. It’s very flat. All you have to do is have made a couple of contributions, and say, “I want to be part of the working group.” And we’ll bring you into the working group, and you can then hang out in the smaller channels that we use of discussing strategy, and figuring out how to do releases… And we talk about marketing, and conferences… That itself is involvement. And, I guess, inspiring us. That’s the thing that really keeps me going, is going on Twitter or GitHub when someone goes to our awesome Tauri repo and makes a PR, and seeing the crazy things that everyone is building - it’s an inspiration and a kind of support that is more important than a financial support. Because open source engineers love seeing the stuff that you’re doing with the work that they’re doing, and that drives them to make it better, and listen to your requests.
Yeah. I love that trend of awesome- whatever technology, and just like accumulating a list of things like that. So it’s really awesome to hear that that’s there for Tauri. That said, can you think of any unique or interesting use cases of Tauri off the top of your head?
Off the top of my head? One of the projects that we’re using is Padlock. So Padlock is password manager, it has teams, and they’re not paying me to say this; it’s just a project that that we love, that’s built on Tauri, that’s open source. Really, really kind of cool. And there was one Galata.app. It’s super-nerdy, and I find a lot of projects these days are scratching the dev’s itch. So if you’re into Kubernetes and you want to track stuff, check out Galata.app. It’s a neat little project with a cute interface, and it frickin’ works.
And there was one more that I found today, Recut is what it’s called. I think it’s getrecut.com. And it’s a really simple app. Basically, it takes all of your video footage and cuts out the parts that are silent. Because if nobody’s talking, nothing’s happening, who the heck cares? And he uses Tauri for the user interface; it’s not open source… Again, not being paid by anybody to do this. It’s just fun to see that tools are being built, because that’s ultimately where Tauri comes from - this drive to make a better tool, to make it useful for people, and to put the power back in our hands.
[00:51:12.22] Yeah, this is really cool. I’m looking at Recut, and - I mean, it’s just a cool, unique example of something that’s not just forms over data. And it’s doing a lot, which is really cool.
One other really interesting one is – so at our Discord we have a channel that’s open to everybody, it’s called Showcase… And in the Showcase you can talk about the apps that you’ve made, and there’s one called Cursus. And Cursus is really cool. They’ve been around with us for like two years, and what Cursus is doing is making speech-to-text and text-to-speech for OBS and VR chat… Which, if you’re into streaming or you have a speech impediment of some kind, it’s an utterly, utterly useful tool. I don’t know if I have a link for it… Yeah, I can paste that in our chat here. Cursus.
Awesome. Yeah, this is super-cool. Well, so for the folks who are interested in looking at Tauri, what’s coming down the pipe? You talked about Tauri 1.0. What’s going to be in 2.1, or what are you excited about that’s coming in Tauri soon?
Well, 1.0 brought desktop and basically the validation that we deserve to exist. 2.0 is bringing in mobile. So for Android, iOS, and I believe we’re also going to support Fdroid, you’ll be able to use the same API interface that you’re used to for Tauri desktop, and build and ship those apps for mobile.
There’s a refactor of the API that came about because of the permissions system for mobile, that means in order to keep parity we have to revise… But along those lines, we’re also making our plugin system available not only to the WebView, but also to the Rust side of things.
What else am I particularly excited about? Well, I am really, really, really, really excited about our foundation. It’s going to have new members joining the summer. In July we’ll have the new votes, and we’re hoping to bring in more people from the community. And I heard there’s a company somewhere out there that is working toward providing Tauri services. So expect them to come out of hiding sometime this summer, so that you’ll get your one-click deploy for Tauri apps. Yeah, it’s great to see the ecosystem growing around it.
Awesome. Well, I think we’ve covered a lot of ground, but I’m definitely excited to go and check out Tauri a little bit more. A lot of good stuff in here. Amazing. Daniel, anything else you want to leave our listeners with before we wrap up?
It does seem to be a trend, too.
Yeah, definitely. Rust is definitely a growth area. Awesome. Well, with that, I think that wraps up our Tauri on JS Party episode. Thank you, Nick. Thank you, Daniel. This is Kball, signing out. We’ll see you next week, same time, same place, on the party.
Our transcripts are open source on GitHub. Improvements are welcome. 💚