Get started making desktop apps using Rust and React

Kent
7 min readJun 29, 2021

--

I have finally found a way to make a desktop app using ReactJS and Rust that’s relatively painless and without too much extra tooling. The key ingredient is called Tauri.

I wrote this post because I couldn’t find any straightforward explanation for initializing a React and Tauri app. Also I wanted to write this down for me to remember how to do this. Hopefully this helps you too.

If you find anything wrong, needs updating, or a better way of doing things; post a comment.

The following instructions have worked for me running on Mac OS 11.4.0 X64 with Node.js 16.4.0, Rust 1.53 and Tauri 1.0.0-beta.4.

What is Tauri?

Tauri is an Electron replacement for packaging a desktop app using ReactJS frontend as a user interface and an optional Rust backend. You can package an app using only Javascript but also have the option to write more performant functions in Rust. For more information, check out their Github at https://github.com/tauri-apps/tauri.

Init a ReactJS app using npm

First, cd to parent directory where the root directory of the app will be located, ie: /home/me/src. Use the following command to generate the react directory structure:

$ npx create-react-app <app-name>

This will create a directory /home/me/src/app-name with subdirectories node_modules, public and src.
The React app source will be in /home/me/src/app-name/src.
The package.json will be in /home/me/src/app-name/package.json.

Install Tauri CLI as a dev dependency

Next cd into the app directory /home/me/src/app-name/src and run the following command:

$ npm install -D @tauri-apps/cli

Edit package.json to add Tauri commands in npm

Open package.jsonand look for the scriptskey. From a fresh init using create-react-app it should look like this:

{
...
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
...
}

Add the “tauri” and “bundle” entries so that it looks like this:

{
...
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"tauri": "tauri",
"bundle": "tauri build"

},
...
}

Init a Tauri inside the React app directory structure

While inside the app directory /home/me/src/app-name, run the following command:

$ npm run tauri init

This will download some things and then will start an interactive prompt with the following questions (you can change these values later):

  1. “What is your app name?”
    The default value will be the value of name in your package.json. Enter a name or press enter for default.
  2. “What should the window title be?”
    Default value will be your app name. Enter a name or press enter for default.
  3. “Where are your web assets (HTML/CSS/JS) located, relative to the <current dir>/src-tauri folder that will be created?”.
    Default value should be ../build.
    Enter ../build if this is not the default value.
  4. “What is the url of your dev server?”
    Default value will be http://localhost:3000.
    Change this to http://0.0.0.0:3000 as recommended in https://github.com/tauri-apps/tauri/issues/1140#issuecomment-848874865.

After answering these questions, it will download a few more things and will install dependencies that are not yet present.

Once finished, a new subdirectory src-tauri should be present inside the app directory, ie. /home/me/src/app-name/src-tauri.

[OPTIONAL] How to edit your answers you made above

If you made a mistake or want to change your app name etc. during the previous step, you can change the values by editing the tauri.conf.json file. It should be located inside the src-tauri subdirectory at /home/me/src/app-name/src-tauri/tauri.conf.json.

Edit answers to question number:

  1. “What is your app name?” value should be in package > productName.
  2. “What should the window title be?” value should be in tauri > windows > title.
  3. “Where are your web assets (HTML/CSS/JS) located…” should be in build > distDir.
  4. “What is the url of your dev server?” should be in build > devPath.

Run a development build of your React-Tauri app (Method A)

First, make sure you are not running anything that is using the http://localhost:3000 URL.

Update: I learned there is another (more convenient?) way to run both the create-react-app dev server and the Tauri dev server. Skip to “Method B” for details.

Open a terminal window and cd to your React app directory, ie. /home/me/src/app-name.

Run your react app with the command:

$ npm start

This will automatically open a browser window pointing to http://localhost:3000 and should show your app.
If working from a fresh init from create-react-app, this should show an animated ReactJS logo and the “Edit src/App,js and save to reload” message.

Then, open a different terminal window and cd to your your React app directory again, ie. /home/me/src/app-name.

Run a Tauri dev build using the following command:

$ npm run tauri dev

The first time you run npm run tauri dev, it will take a while as it will download and build all of Tauri’s Rust dependencies. Subsequent builds should run faster as the dependencies are now built and cached.

Once Rust is finished building the dependencies (if running for the first time) and your Rust code, a webview should open displaying your app exactly like what the browser window should previously.

Changes made to the React app will be automatically reflected thanks to the dev server from using create-react-app. Changes made to the Rust code will trigger a rebuild and will restart the app to reflect the changes.

Run a development build of your React-Tauri app (Method B)

The other way to run a dev build is to let Tauri dev build script run the command to start the create-react-app dev server before making a dev build. In short, you just need a single command to run both React and Rust development builds.

To do this, edit the tauri.conf.json file located at /home/me/src/app-name/src-tauri/tauri.conf.json based on my sample directory structure. Look for the build > beforeDevCommand and add npm start such that it looks like this:

{
...
"build": {
"distDir": "../build",
"devPath": "http://0.0.0.0:3000",
"beforeDevCommand": "npm start",
"beforeBuildCommand": ""
},
...
}

Then just like above, run a Tauri dev build using the following command:

$ npm run tauri dev

With this change, this should be equivalent to calling npm start and npm run tauri dev consecutively. All the features and caveats of running them separately applies to running them through the beforeDevCommand method.

While it is convenient to start using a single command, the downside is that the React dev server continues on running even after you terminate the Tauri live development build. This means you will have to hunt down the node process running it and manually killing it. Not so convenient after all.

From my experience, it is better to use Method A for making a dev build. This means running the React dev server and the Tauri live build in separate terminal sessions.

Make a release build of your React-Tauri app (Method A)

Update: Just like the dev build shortcut, there is another more convenient way to make a release build for both your React app and the Tauri app with a single command. Read “Method B” below for details.

Open a terminal window and cd to your React app directory, ie. /home/me/src/app-name.

Make a release build your ReactJS app using the following command:

$ npm run build

Then, make a release build of your Tauri app. This will include the release build of the React app you just made.

Run the following command:

$ npm run bundle

or

$ npm run tauri build

Make a release build of your React-Tauri app (Method B)

Similar to Method B in making a development build, there is a way that creates a release build of your React app, Tauri and your Rust code with just a single command.

Open the tauri.conf.json file located at /home/me/src/app-name/src-tauri/tauri.conf.json. Edit build > beforeBuildCmmmand and add npm run bundlesuch that it looks like this:

{
...
"build": {
"distDir": "../build",
"devPath": "http://0.0.0.0:3000",
"beforeDevCommand": "npm start",
"beforeBuildCommand": "npm run build"
},
...
}

Then, use the following command to create a release build:

$ npm run tauri dev

or

$ npm run tauri build

Just as in the dev build shortcut, this is equivalent to calling npm run build and then subsequently calling npm run tauri build. However, unlike the alternate dev build method, there is no downside to this as npm run build will terminate after it is done building your React app. This one is actually convenient.

Release build files

Making a release build will create a subdirectory /home/me/src/app-name/src-tauri/target/release , if it wasn’t present before. Otherwise, it will overwrite files that needs to be recompiled.

  1. /home/me/src/app-name/src-tauri/target/release/productName where productName was your answer in question 1 when initializing Tauri. This can be launched from the command line.
  2. /home/me/src/app-name/src-tauri/target/release/bundle/macos/productName.app will be a Mac OS .app file that you can double-click to launch.
  3. /home/me/src/app-name/src-tauri/target/release/bundle/macos/productName_…_.dmg will be a Mac OS .dmg file that you can double-click to install.

And there you have it.

Play around with the GUI by modifying the React Javascript code in /home/me/src/app-name/src/App.js or the make your own Javascript callable Rust functions by modifying /home/me/src/app-name/src-tauri/src/main.rs . Visit https://tauri.studio/en/docs/usage/guides/command for more details on how to make your own Rust commands.

To learn more about the Tauri project, ReactJS and programming in Rust:

I’m quite excited to play around with this and I hope to share more of what I learn.

--

--

Kent

Python, finance, science, technology and life of a computational biologist