How To Create Small, Fast And Cool Desktop Apps With Tauri And Ember.js

Written by mitchartemis | Published 2021/06/04
Tech Story Tags: rust | ember | javascript | electron | coding | software-development | tauri | application

TLDR Tauri is a toolkit for development desktop apps with web technologies. Here's how I got it working with an Ember.js application. It's built in Rust rather than Javascript and uses your operating system's native web browser rather than bundling Chrome. It works even with hot reloading! I'm excited to see where Tauri goes, and to see its plugin ecosystem grow. I thought I'd test a simple ping/pong example of communicating between Ember and Rust. For more information check the Tauri docs.via the TL;DR App

I recently played around with Tauri, a toolkit for development desktop apps with web technologies. Here's how I got it working with an Ember.js application.

What is Ember?

Ember.js is a frontend framework similar to React and Vue JS. I used it to build my app Snipline, and it's also used for websites like Intercom and LinkedIn. It has a 'convention over configuration' approach similar to Ruby on Rails.

What is Tauri?

Tauri is a library for making desktop applications with web technologies. Similar to Electron with a few key differences:
1) It's built in Rust rather than Javascript.
2) It uses your operating system's native web browser rather than bundling Chrome which resulting in quite tiny applications—at least compared to Electron!

Installation and development

Here are the commands I ran for a simple Ember app to test routing with Ember and Tauri. For reference, I'm using Node. 14.17.0.

Setting up Ember

npm install -g ember-cli
ember new tauri-test --lang en
ember g route index
ember g route from-ember
ember serve
I edited the two generated templates,
app/templates/index.hbs
and
app/templates/from-ember.hbs
.
{{page-title "Index"}}
<h1>Hello, Tauri 😄</h1>
<LinkTo @route="from-ember">Click here</LinkTo>
{{page-title "FromEmber"}}
<h1>From Ember 🧡</h1>
<LinkTo @route="index">Back</LinkTo>
That's enough to get started and test that routing works within the app. Now let's get to the good stuff.

### Setting up Tauri

After this, it's a matter of adding it to your ember project - See the integration documentation.
This is what I did to get it working.
npm install @tauri-apps/cli
// Add the `tauri` command to your `package.json`
{
  // This content is just a sample
  "scripts": {
	"tauri": "tauri"
  }
}
Run through the initialisation process.
npm run tauri init
When prompted, make sure that you set the development server to
http://localhost:4200
and the location of the files (relative to
src-tauri
) to
../dist
.
Then it's just a matter of running the development subcommand (Make sure your Ember server is still up, too).
npm run tauri dev
And that's it! It works even with hot reloading!

Packaging

With development out of the way, here's how to package the app for distribution. I won't be looking at auto-updates in this guide, but Tauri does have support for this.
ember build --environment=production
npm run tauri build
On MacOS installer
.dmg
file came out at 5.4MB and the
.app
file 12.4MB.
For Windows, the generated MSI installer came to 4.9MB and the executable 8.9MB.

Communicating between Rust and Ember

Taking this one step further, I thought I'd test a simple ping/pong example of communicating between Ember and Rust. For more information check the Tauri docs.
The following code allows for Ember to pass a string to Rust, Rust checks the value and toggles between the text 'Ping' and 'Pong'. In Ember, I've added a button that displays the response text and updates it on click.
// src-tauri/src/main.rs
#![cfg_attr(
  all(not(debug_assertions), target_os = "windows"),
  windows_subsystem = "windows"
)]
// Add a new function that takes a string and returns a string
#[tauri::command]
fn my_custom_command(current_text: String) -> String {
	// Depending on what we receive from Ember we toggle the response
	if current_text == "Ping" {
		"Pong!".into()
	} else {
		"Ping".into()
	}
}
fn main() {
  // Add the custom command so that the frontend can invoke it
  tauri::Builder::default()
	.invoke_handler(tauri::generate_handler![my_custom_command])
	.run(tauri::generate_context!())
	.expect("error while running tauri application");
}
// app/controllers/index.js
import Controller from '@ember/controller'
import { action } from '@ember/object'
import { tracked } from '@glimmer/tracking'
import { invoke } from '@tauri-apps/api/tauri'
export default class IndexController extends Controller {
	// Set the default button text
	@tracked buttonText = 'Ping'
	// Create an action that will be attached to a button in the template
	@action
	checkRust() {
		// Invoke the Rust command and update the button text to the response
		invoke('my_custom_command', { currentText: this.buttonText }).then(resp => {
			console.log(resp)
			this.buttonText = resp
		})
	}
}
Here's the updated
app/templates/index.hbs
template file.
{{page-title "Index"}}
<h1>Hello, Tauri 😄</h1>
<LinkTo @route="from-ember">Click here</LinkTo>
<button {{ on 'click' this.checkRust }}>{{this.buttonText}}</button>
Pretty cool! I'm excited to see where Tauri goes, and to see its plugin ecosystem grow. Should I try building a full project in it or write some more tutorials using both technologies?

Published by HackerNoon on 2021/06/04