Creating Tiny Desktop Apps With Tauri And Vue.js
Technology makes our lives better, not just users, but also creators (developers and designers). In this article, I’ll introduce you to Tauri. This article will be useful to you if:
- you have been building applications on the web with HTML, CSS, and JavaScript, and you want to use the same technologies to create apps targeted at Windows, macOS, or Linux platforms;
- you are already building cross-platform desktop apps with technologies like Electron, and you want to check out alternatives;
- you want to build apps with web technologies for Linux distributions, such as PureOS;
- you are a Rust enthusiast, and you’d like to apply it to build native cross-platform applications.
We will look at how to build a native cross-platform application from an existing web project. Let’s get to it!
Note: This article assumes you are comfortable with HTML, CSS, JavaScript, and Vue.js.
What Is Tauri?
The official website sums up Tauri well:
- Tauri is a polyglot toolchain for building more secure native apps with both tiny and fast binaries. By “polyglot”, I mean that Tauri uses multiple programming languages. At the moment, Rust, JavaScript, and TypeScript are used. But there are plans to let you use Go, C++, Python, and more.
- It lets you use any HTML and JavaScript-based front-end framework, such as Vue.js, React, or Angular, to build a native desktop app, and it can be integrated into any pipeline.
- It helps you build and bundle binaries for major desktop platforms (mobile and WebAssembly coming soon).
So, basically, Tauri allows you to use web technologies to create tiny and secure native desktop apps.
On its GitHub page, Tauri is described as a framework-agnostic toolchain for building highly secure native apps that have tiny binaries (i.e. file size) and that are very fast (i.e. minimal RAM usage).
Why Not Electron?
A popular tool for using web technologies to build desktop applications is Electron.
However, Electron apps have a rather large bundle size, and they tend to take up a lot of memory when running. Here is how Tauri compares to Electron:
- Bundle
The size of a Tauri app can be less than 600 KB. - Memory
The footprint of a Tauri app is less than half the size of an Electron app. - Licence
Relicensing is possible with Tauri, but not with Electron. Electron ships with Chromium right out of the box. However, Chromium includes a digital rights-management system named Widevine. The inclusion of Widevine in Chromium makes apps created with Electron frowned upon by users of platforms such as PureOS for the sole reason that it is not free/libre open-source software (FLOSS). Platforms like PureOS are verified by the Free Software Foundation (FSF). This means that they can only publish free and open-source software in their app stores.
In a nutshell, if your app is built with Electron, it will never be shipped officially in the PureOS store. This should be a concern for developers targeting such distributions.
More Features Of Tauri
- Security is really important to the Tauri team. Apps created with Tauri are meant to be secure from the get-go.
- Tauri is compatible with any front-end framework, so you don’t have to change your stack.
- It has many design patterns to help you choose important features with simple configurations.
Pros Of Tauri
- Tauri enables you to take the code base you’ve built for the web and turn it into a native desktop app, without changing a thing.
- Although you could use Rust in a Tauri-based project, it is completely optional. If you did, you wouldn’t need to change anything in your original code base targeted for the web.
Real-World Tauri
If you have been part of the Vue.js community for a while, then you’ll have heard of Guillaume Chau, a member of the core team of Vue.js. He is responsible for the Vue.js command-line interface (CLI), as well as other awesome Vue.js libraries. He recently created guijs, which stands for “graphical user interface for JavaScript projects”. It is a Tauri-powered native desktop app to visually manage your JavaScript projects.
Guijs is an example of what is possible with Tauri, and the fact that a core member of the Vue.js team works on the app tells us that Tauri plays nicely with Vue.js (amongst other front-end frameworks). Check out the guijs repository on GitHub if you are interested. And, yes, it is open-source.
How Tauri Works
At a high level, Tauri uses Node.js to scaffold an HTML, CSS, and JavaScript rendering window as a user interface (UI), managed and bootstrapped by Rust. The product is a monolithic binary that can be distributed as common file types for Linux (deb/appimage), macOS (app/dmg), and Windows (exe/msi).
How Tauri Apps Are Made
A Tauri app is created via the following steps:
- First, make an interface in your GUI framework, and prepare the HTML, CSS, and JavaScript for consumption.
- The Tauri Node.js CLI takes it and rigs the Rust runner according to your configuration.
- In development mode, it creates a WebView window, with debugging and Hot Module Reloading.
- In build mode, it rigs the bundler and creates a final application according to your settings.
Setting Up Your Environment
Now that you know what Tauri is and how it works, let me walk you through setting up your machine for development with Tauri.
Note: The setup here is for Linux machines, but guides for macOS and for Windows are also available.
Linux Setup
The polyglot nature of Tauri means that it requires a number of tool dependencies. Let’s kick it off by installing some of the dependencies. Run the following:
$ sudo apt update && sudo apt install libwebkit2gtk-4.0-dev build-essential curl libssl-dev appmenu-gtk3-module
Once the above is successful, proceed to install Node.js (if you don’t already have it), because Tauri requires its runtime. You can do so by running this:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
This will install nvm (Node.js version manager), which allows you to easily manage the Node.js runtime and easily switch between versions of Node.js. After it is installed, run this to see a list of Node.js versions:
nvm ls-remote
At the time of writing, the most recent version is 14.1.0. Install it like so:
nvm install v14.1.0
Once Node.js is fully set up, you would need to install the Rust compiler and the Rust package manager: Cargo. The command below would install both:
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
After running this command, make sure that Cargo and Rust are in your $PATH
by running the following:
rust --version
If everything has gone well, this should return a version number.
According to the Tauri documentation, make sure you are on the latest version by running the following command:
$ rustup update stable
Voilà! You are one step closer to getting your machine 100% ready for Tauri. All that’s left now is to install the tauri-bundler
crate. It’s best to quit your CLI, and run the command below in a new CLI window:
$ cargo install tauri-bundler --force
Eureka! If everything went all right, your machine is now ready for Tauri. Next up, we will get started integrating Tauri with Vue.js. Let’s get to it!
Yarn
The Tauri team recommends installing the Yarn package manager. So let’s install it this way:
npm install -g yarn
Then run the following:
yarn --version
If everything worked, a version number should have been returned.
Integrating Tauri With Vue.js
Now that we have Tauri installed, let’s bundle an existing web project. You can find the live demo of the project on Netlify. Go ahead and fork the repository, which will serve as a shell. After forking it, make sure to clone the fork by running this:
git clone https://github.com/[yourUserName]/nota-web
After cloning the project, run the following to install the dependencies:
yarn
Then, run this:
yarn serve
Your application should be running on localhost:8080
. Kill the running server, and let’s install the Vue.js CLI plugin for Tauri.
vue-cli-plugin-tauri
The Tauri team created a Vue.js CLI plugin that quickly rigs and turns your Vue.js single-page application (SPA) into a tiny cross-platform desktop app that is both fast and secure. Let’s install that plugin:
vue add tauri
After the plugin is installed, which might take a while, it will ask you for a window title. Just type in nota
and press “Enter”.
Let’s examine the changes introduced by the Tauri plugin.
package.json
The Tauri plugin added two scripts in the scripts section of our package.json
file. They are:
"tauri:build": "vue-cli-service tauri:build",
"tauri:serve": "vue-cli-service tauri:serve"
The tauri:serve
script should be used during development. So let’s run it:
yarn tauri:serve
The above would download the Rust crates needed to start our app. After that, it will launch our app in development mode, where it will create a WebView window, with debugging and Hot Module Reloading!
src-tauri
You will also notice that the plugin added a src-tauri
directory to the root of your app directory. Inside this directory are files and folders used by Tauri to configure your desktop app. Let’s check out the contents:
icons/
src/
build.rs
cmd.rs
main.rs
Cargo.lock
Cargo.toml
rustfmt.toml
tauri.conf.json
tauri.js
The only change we would need to make is in src-tauri/Cargo.toml
. Cargo.toml
is like the package.json
file for Rust. Find the line below in Cargo.toml
:
name = "app"
Change it to this:
name = "nota"
That’s all we need to change for this example!
Bundling
To bundle nota
for your current platform, simply run this:
yarn tauri:build
Note: As with the development window, the first time you run this, it will take some time to collect the Rust crates and build everything. On subsequent runs, it will only need to rebuild the Tauri crates themselves.
When the above is completed, you should have a binary of nota
for your current OS. For me, I have a .deb
binary created in the src-tauri/target/release/bundle/deb/
directory.*
Going Cross-Platform
You probably noticed that the yarn tauri:build
command just generated a binary for your operating system. So, let’s generate the binaries for other operating systems. To achieve this, we will set up a workflow on GitHub. We are using GitHub here to serve as a distribution medium for our cross-platform app. So, your users could just download the binaries in the “Release” tab of the project.
The workflow we would implement would automatically build our binaries for us via the power of GitHub actions. Let’s get to it.
Creating The Tauri Workflow
Thanks to Jacob Bolda, we have a workflow to automatically create and release cross-platform apps with Tauri on GitHub. Apart from building the binary for the various platforms (Linux, Mac, and Windows), the action would also upload the binary for you as a release on GitHub. It also uses the Create a Release action made by Jacob to achieve this.
To use this workflow, create a .github
directory in the root of nota-web
. In this directory, create another directory named workflows
. We would then create a workflow file in .github/workflows/
, and name it release-tauri-app.yml
.
In release-tauri-app.yml
, we would add a workflow that builds the binaries for Linux, macOS, and Windows. This workflow would also upload the binaries as a draft release on GitHub. The workflow would be triggered whenever we push to the master.
Open release-tauri-app.yml
, and add the snippet below:
name: release-tauri-app
on:
push:
branches:
- master
paths:
- '**/package.json'
jobs:
check-build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
— uses: actions/checkout@v2
— name: setup node
uses: actions/setup-node@v1
with:
node-version: 12
— name: install rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
— name: install webkit2gtk
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0
— run: yarn
— name: build nota for tauri app
run: yarn build
— run: cargo install tauri-bundler --force
— name: build tauri app
run: yarn tauri:build
create-release:
needs: check-build
runs-on: ubuntu-latest
outputs:
RELEASE_UPLOAD_URL: ${{ steps.create_tauri_release.outputs.upload_url }}
steps:
— uses: actions/checkout@v2
— name: setup node
uses: actions/setup-node@v1
with:
node-version: 12
— name: get version
run: echo ::set-env name=PACKAGE_VERSION::$(node -p "require('./package.json').version")
— name: create release
id: create_tauri_release
uses: jbolda/create-release@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ matrix.package.name }}-v${{ env.PACKAGE_VERSION }}
release_name: 'Release nota app v${{ env.PACKAGE_VERSION }}'
body: 'See the assets to download this version and install.'
draft: true
prerelease: false
create-and-upload-assets:
needs: create-release
runs-on: ${{ matrix.platform }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
include:
— platform: ubuntu-latest
buildFolder: bundle/deb
ext: \_0.1.0_amd64.deb
compressed: ''
— platform: macos-latest
buildFolder: bundle/osx
ext: .app
compressed: .tgz
— platform: windows-latest
buildFolder: ''
ext: .x64.msi
compressed: ''
steps:
— uses: actions/checkout@v2
— name: setup node
uses: actions/setup-node@v1
with:
node-version: 12
— name: install rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
— name: install webkit2gtk (ubuntu only)
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0
— run: yarn
— name: build nota for tauri app
run: yarn build
— run: cargo install tauri-bundler --force
— name: build tauri app
run: yarn tauri:build
— name: compress (macos only)
if: matrix.platform == 'macos-latest'
working-directory: ${{ format('./src-tauri/target/release/{0}', matrix.buildFolder ) }}
run: tar -czf ${{ format('nota{0}{1}', matrix.ext, matrix.compressed ) }} ${{ format('nota{0}', matrix.ext ) }}
— name: upload release asset
id: upload-release-asset
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.RELEASE_UPLOAD_URL }}
asset_path: ${{ format('./src-tauri/target/release/{0}/nota{1}{2}', matrix.buildFolder, matrix.ext, matrix.compressed ) }}
asset_name: ${{ format('nota{0}{1}', matrix.ext, matrix.compressed ) }}
asset_content_type: application/zip
— name: build tauri app in debug mode
run: yarn tauri:build --debug
— name: compress (macos only)
if: matrix.platform == 'macos-latest'
working-directory: ${{ format('./src-tauri/target/debug/{0}', matrix.buildFolder ) }}
run: tar -czf ${{ format('nota{0}{1}', matrix.ext, matrix.compressed ) }} ${{ format('nota{0}', matrix.ext ) }}
— name: upload release asset with debug mode on
id: upload-release-asset-debug-mode
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.RELEASE_UPLOAD_URL }}
asset_path: ${{ format('./src-tauri/target/debug/{0}/nota{1}{2}', matrix.buildFolder, matrix.ext, matrix.compressed ) }}
asset_name: ${{ format('nota-debug{0}{1}', matrix.ext, matrix.compressed ) }}
asset_content_type: application/zip
To test the workflow, commit and push your changes to your fork’s master
branch. After successfully pushing to GitHub, you can then click on the “Actions” tab in GitHub, then click on the “Check build” link to see the progress of the workflow.
Upon successful execution of the action, you can see the draft release in “Releases” on the repository page on GitHub. You can then go on to publish your release!
Conclusion
This article has introduced a polyglot toolchain for building secure, cross-platform, and tiny native applications. We’ve seen what Tauri is and how to incorporate it with Vue.js. Lastly, we bundled our first Tauri app by running yarn tauri:build
, and we also used a GitHub action to create binaries for Linux, macOS, and Windows.
Let me know what you think of Tauri — I’d be excited to see what you build with it. You can join the Discord server if you have any questions.
The repository for this article is on GitHub. Also, see the binaries generated by the GitHub workflow.
Further Reading
- Building Complex Forms In Vue
- The Era Of Platform Primitives Is Finally Here
- Best Of Pro Scheduler Libraries
- The Modern Guide For Making CSS Shapes