Introduction
This is the first article of a series about learning Tauri through a practical project. But it will also be about learning some Rust.
In fact, at the end of 2023 I decided in 2024 i would learn Rust, so I started studying it; but as often happens, comes the problem to put your knowledge in action with some practical project, and it can be difficult if you have not the right idea.
Luckily enough I heard about Tauri.
Tauri is a toolkit that let you build Desktop application for any OS, writing the core in Rust and using nearly any Js framework (or none at all) to build your frontend.
It seemed the perfect fit to put in action my web developer knowledge to work on the frontend while training and improving my brand new language for the backend: Rust.
As another lucky coincidence, I was pretty tired of some repetitive steps i have to take each week when i publish my newsletter. After writing it in Italian Markdown i needed to convert it in html, translate it in english, convert also the new version in html. prepare both on Brevo and Devto... Gosh, I'm a developer, I'm supposed to automate those stuff! So let's do this! I built my own platform for handling all those tasks automatically.
So in these articles I'll guide you trough the steps I took to get to the actual result, with the goal to help you improve both your knowledge of Rust and Tauri at the same time, as this project did for me!
So, enough with the chit-chat! Let's start!
First steps
First of all you will, of course, need Rust and Cargo installed on your machine. If you haven't yet you can find here more indications on the best way to do it.
Once you have them installed, we can initialize our project by running
cargo install create-tauri-app --locked # only needed the first time to install create-tauri-app tool
cargo create-tauri-app
You will be guided trough a small wizard that will let you pick your favourite stack.
N.B.
For this series of articles I'll be using Vue and TyprScript for the front-end but, as mentioned, you can use whichever tech stack you prefer for the frontend. I won't be focusing on that part a lot except for when is needed for the Tauri flow comprehension
So you follow instructions and you enter your folder.
Files and folders
As we start our project we can see, as always that a bunch of files and folders were created. Specifically we will be working in a couple of them: src
, which will contain all the frontend code and src-tauri
, containing all the backend Rust code.
The src
folder is quite much the typical one you could find in your web projects; there are components, assets, and so on. So let's focus on the src-tauri
folder and let's see what we can find there.
Cargo.toml
If you are new to the Rust enviroment, the Cargo.toml file contains all the project information and dependencies: it is pretty much like the package.json file for node projects
Tauri.conf.json
This file contains actually some cool config stuff.
First of all contains some dev and build commands, which you can leave as they are for the moment. Then you can find your package info, like the productName
i.e. the name of your project and the version
. After that, under the tauri
key, you will find some default defined items. This is actually interesting because contains many valuable configurations for our app.
First of all there's allowlist, which is a transposition of Cargo's equivalent feature in order choose whether enable access to certain system functionalities like filesystem, shell, http and so on or not.
This is a security-focused configuration, because there's no way a tauri project can access some functionalities if it's not explicitly specified in this section. This means you can choose your app capabilites really in detail, to make it safe.
Then comes the bundle config, with all the relevant information about your bundled application. The only required parameter is the identifier that must be unique. Apart from that, you can specify your application icons, the building target and more stuff.
Last thing we'll look into in this file will be the windows
which specifies configurations about our windows: size, position, title whether if they're resizable or not and so on.
src
folder
This is the folder where the core part of our application lives. Inside of it we will find a main.rs
file that already contains some lines of code to start with. So let's look into it!
main.rs: our starting point
So we open our main.rs file to get our hands dirty! What do we stumble upon ?
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
Clearly it is a function but the line above instead is a pretty common thing to find in Rust: it's called an attribute and generally can define some metadata about the function or structure that follows. There are many of them, if you're not familiar with Rust or with attributes I suggest you to give it a look at the official documentation.
We won't be using them a lot in these article but it's a great feature to know when working in Rust ( to give you an idea you can directly specify that a function is a test function thanks to them, this makes tremendously easy to create tests in your code).
So, what this #[tauri::command]
attribute is about?
it specify that the following is a function callable from our frontend, directly from js. We can return to our frontend whatever type we like, in this case it's a String; the only condition is that it shall derive the Serde::Serialize
trait. We'll dive deeper into this later in the series
Next, a couple lines below, you can find this:
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
these lines are the actual launcher of our application. When we want to add something right in the moment the project starts, we'll work in this part.
For example if we mean to have multiple windows, or a window menu etc... we can initialize those the main function.
For this introduction, let's just notice one thing:
.invoke_handler(tauri::generate_handler![greet])
this line allow us to define which functions among the ones using #[tauri::command]
attribute can actually be called by the frontend.
So when we want to create a new function callable by the front-end, me both need to use the attribute and to add them to the generate_handler
array.
A quick look at the frontend
So, until now we looked into our backend. What about the frontend? How do we invoke rust functions?
As you can see opening the src
folder in your project's root, you'll see the common structure of a JS project.
In my case it's a Vue project using TypeScript.
What we're looking for is actually inside the components
folder, where we can find a Greet component.
import { ref } from "vue";
import { invoke } from "@tauri-apps/api/tauri";
const greetMsg = ref("");
const name = ref("");
async function greet() {
greetMsg.value = await invoke("greet", { name: name.value })
}
as we can see the invoke
method is imported from tauri api package.
the invoke function takes two arguments, the first is the function name, the second is an object with the Rust arguments as keys.
Be careful: Rust guidelines asks your variables and parameters to be snake_case, while in this object the keys must be in camelCase; if you try to use snake case here, you'll get an error.
Is this thing written in the doc? Yes.
Did I noticed it first time? Definitely not.
Whatever.
What we get returned from invoke
is a promise, whose result will be exactly what we returned in our function.
Run it
So you can go in the root of the project, install all npm packages with npm install
and then run the example app with npm run tauri dev
.
It will take some time to compile but then you will see the starting point of our adventure up and running.
Conclusion
As said this was the first part of a series; we didn't get our hands dirty, but just got some directions and general ideas of the projects.
Next time we will start building some functionalities, starting by calling some APIs and manipulating results!
Are you up for a coding adventure? I really hope to find you here in the next chapter!
Until next time
Happy Coding 0_1
Top comments (0)