Post

Let's make a App with Scala.js and Tauri part 1

Let's make a App with Scala.js and Tauri part 1

Tauri is a framework for building tiny, fast binaries for all major desktop and mobile platforms. Javascript app will run as if it was running within browser. Let’s make a simple application using scala.js.

Requirements for Tauri

Build tools for each platform, rust and node.js must be installed first. See tauri’s document.

Creation of an application

Tauri supports ways of creating app’s skeleton. We’ll use pnpm. Install it before running following commands. When it runs, it will ask questions to answer. Enter your own identifier for second question.

1
2
3
4
5
6
7
>> pnpm create tauri-app
✔ Project name · tauri-app
✔ Identifier · <your unique identifier>
✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, deno, bun)
✔ Choose your package manager · pnpm
✔ Choose your UI template · Vanilla
✔ Choose your UI flavor · JavaScript

CD into the project folder and install packages. Then make an application and run it. A window with icons and simple form will be shown.

1
2
3
>> cd tauri-app
>> pnpm instal
>> pnpm tauri dev

default tauri app

Structure of the project folder

Simplified structure of the project folder with important files are as follows

1
2
3
4
5
6
7
8
+- src : where our javascript app will be located
|  - index.html : skeleton of app
|  - main.js : javascript referenced in index.html
+- src-tauri : tauri's code in rust
|  - Cargo.toml : build configuration for rust
|  - tauri.conf.json : our tauri app's meta information and configuration
+- node_modules : handled by pnpm
- package.json : package file for node.js

Let Scala render the screen

Now it’s time for scala.js. I will use mill as a build tool and scalatags for HTML. Welcome to Li Haoyi world.

install mill

As mill’s installation page, the standard method of installing mill is to install mill script at project folder. I’ve had problem running mill in Windows and had to edit mill.bat to change default mill version. Following will work in macOS and linux.

1
2
3
>> curl -L https://repo1.maven.org/maven2/com/lihaoyi/mill-dist/0.13.0-M0/mill -o mill
>> chmod +x mill
>> echo 0.12.8 > .mill-version

Mill’s build file is build.sc and mill requires separate source folder.

1
2
3
>> touch build.sc
>> mkdir -p front/src
>> touch front/src/Front.scala
build.sc

Object front in build.sc matches the folder name. All source files, resources and test files reside within that folder. fscala task compiles scala code and copies the resulting javascript codes to src folder. mill’s build file is using scala 2.13 syntax, so square brackets are needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import mill._, scalalib._, scalajslib._

object front extends ScalaJSModule {
    def scalaVersion = "3.6.3"
    def scalaJSVersion = "1.18.2"
    def ivyDeps = Agg(ivy"com.lihaoyi::scalatags::0.13.1")
	def fscala = Task {
		val jsPath = front.fastLinkJS().dest.path
		val targetPath = jsPath / os.up / os.up / os.up / "src"
		val target = targetPath / "main.js"
		os.copy.over(jsPath / "main.js", target)
		os.copy.over(jsPath / "main.js.map", targetPath / "main.js.map")
		PathRef(target)
    }
}
Front.scala

Using scalatags to render into document’s boby. The structure of tags are same as original index.html.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import org.scalajs.dom
import scalatags.JsDom.all.*

object Front:
    def main(args: Array[String]): Unit = 
        // render tags into body
        dom.document.body.appendChild(content.render)

    val content = 
        tag("main")(cls := "container",
            h1(s"Welcome to Tauri with Scala.js"),
            div(cls := "row",
                a(href := "https://tauri.app",
                    target := "_blank",
                    img(src := "/assets/tauri.svg", cls := "logo tauri", alt := "Tauri logo")),
                a(href := "https://developer.mozilla.org/en-US/docs/Web/JavaScript",
                    target := "_blank",
                    img(src := "/assets/javascript.svg", cls := "logo vanilla", alt := "JavaScript logo"))
            ),

            p("Click on the Tauri logo to learn more about the framework"),

            form(cls := "row", id := "greet-form",
                input(id := "greet-input", placeholder := "Enter a name..."),
                button(`type` := "submit", "Greet")),
            p(id := "greet-msg")
        )
index.html

Remove all tags in body.

1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="styles.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tauri App</title>
    <script type="module" src="/main.js" defer></script>
  </head>
  <body>
  </body>
</html>

First line compiles scala to javascript code and copy it to src folder.

1
2
>> ./mill front.fscala
>> pnpm tauri dev

Now app’s appearance is same as initial code, but screen is rendered from scala code. Greet button does not work as previously. This functionality requires calling Tauri’s API, which will be handled at part 2.

This post is licensed under CC BY 4.0 by the author.