Making a Desktop app with Elm, Deno & Velociraptor (and now Tauri)

I’ve set things up for Tauri with some help from their dev team on Discord. About 30 min from the time I started reading the docs to bringing up the app with npx tauri dev. I am impressed. A pretty straightforward, painless and successful process.

Tauri has a full file API, so I think that I am going to be able to do what I want with this.

PWA means Progressive web application (Wikipedia).

1 Like

Also: Public Works Administration, created in 1933 by Franklin Roosevelt. :grinning:

1 Like

Does a webview offer more APIs than a webbrowser? For my understanding (but I am not sure) a webview is a webbrowser without decoration, bookmarks and so on. So I assume, there is no API for accessing the local filesystem.

There is a draft for a Native File API, so there are chances, that in the future such an API will be available.

@hans-helmut you’re thinking of a PWA. A webview is a native app that uses the browser engine for the UI. For example, on a Mac the webview is always webkit and on Windows it’s either IE or Edge (I think trident, not blink). It’s similar to electron but actually native.

Re Tauri:

Anyone out there who has built an Elm desktop app with Tauri?

I am struggling with how access Tauri’s JS file API using ports. I have file outside.js that is referenced by Elm’s index.html. According to the Tauri docs, one could say

import { readTextFile, writeFile } from 'tauri/api/fs'
import { open, save } from 'tauri/api/dialog'

Or one could use require. But those are ES6 and node syntaxes respectively.

I’ve been advised that one can use browserify. Is that a good way to go?

Report on Tauri

I’d like to report on my experience so far with Tauri. As noted above, the setup process for development went well, and I was able to run the app in development mode with little trouble. There was one non-blocking glitch which turned out to be a bug, but the (very responsive) Tauri core team has already fixed it.

Bundling the app

Bundling the app turned out to be quite simple. I copied the Main.js and index.html files into ./dist as well as the directory ./assets; the latter has one css file and some Javascript files that work with ports and which define some custom elements that talk to a large JS library (MathJax.js). I then ran npx tauri bundle. After a lot of compilation (mostly Rust files, I think), the results were deposited as listed below: an app (which I renamed) and a dmg installer.

$ tree -L 2 src-tauri/target/release/bundle/
src-tauri/target/release/bundle/
├── dmg
│   ├── app.dmg
│   ├── bundle_dmg.sh
│   └── support
└── osx
    └── muEdit.app

If you say “show package contents” for the app, you find the file Contents/MacOs/app which weighs 4.9 MB. This is the executable. Does anyone know how this compares with Electron?

Note added. There are tools to reduce the size. Maybe able to get to about 1 MB.

Running the app

With two exceptions having to do with JS interop, the app responded normally, and was able to talk to both the localhost server I have been using for data persistence and a remote server. The custom element code worked fine, as did MathJax.js, which is used to render math formulas. The app was very snappy/responsive.

I did get one crash, but have not been able to duplicate it.

((Turns out that using a localhost server for persistence as I have done is a well-known bad which was pointed out to me by @miniBill and @wolfadex and also referenced in something I read about Tauri.))

What did not work

The two things that did not work had to do with copy-paste between the external world and the app. This uses ports and some JS code which is not part of the Tauri JS API — one gets undefined in the console. Here is some of the code:

    function updateClipboard(newClip) {
      console.log("updateClipboard")
      navigator.clipboard.writeText(newClip).then(function() {
      }, function() {
        console.log ("!JS! Clipboard write failed");
      });
    }

It is navigator that gave the undefined message.

Next steps

The next step is to implement file system access and use it to persist the documents that the app works on. For that I will need to figure out how to use the Tauri JS API. This will be slightly tricky since I will have to use require and hence rely on browserify — unless someone has a better suggestion.

(@AlienKevin, if you are around, could you ping me? Tauri also has Rust bindings – and is written in Rust. I’d like to see if the file persistence stuff and maybe some other things can be done using Rust. Tauri does have a Rust API. I can be reached here, as jxxcarlson on Slack, and as jxxcarlson on gmail. Thanks!)

Conclusion

Tauri looks very promising. Still very young (one year and one month): version 0.6.3 (four days ago)

2 Likes

Typically you’d need type="module" to be able to use import in an HTML file:

<script type="module">
import { readTextFile, writeFile } from 'tauri/api/fs'
import { open, save } from 'tauri/api/dialog'
</script>

I have no idea if that works with Tauri, though.

I will try that —would be far more direct. Thanks!

I added the script you suggested. So far, so good. No compilation or runtime errors. Now I have to use, e.g., readFile and see if it really works

I had said above that the Tauri app worked fine with one exception. Actually, no exception: image rendering is fine:

8 Likes

Current work: Adding file access to persist documents on disk instead of using a server on localhost. It is going surprisingly well. I’m really impressed with Tauri.

The Tauri JS API had to be transpiled (Tauri core team did this). I then require that API in a file outside_source.js where the API is used and all the interaction via ports is defined. Before running npx tauri dev, one then has to browserify that file to produce the real outside.js.

Sounds very clunky, but I use Velociraptor to automate the process: Here is the scripts.yaml that vr uses:

scripts:

  tauri:
    cmd:
      - browserify public/assets/outside_source.js -o public/assets/outside.js
      - npx tauri dev
    desc: Run tauri dev

Then I just say vr tauri.

1 Like

Some conclusions in the PPS of this article:

It is now two days since starting my experiment with Tauri. I’ve implemented all the CRUD operations needed to persist documents disk in a designated directory: create, list, read, update, and delete. These operations are carried out by one Elm module,Outside, that talks to one JS file, outside.js via a single pair of ports. (Murphie Randall’s approach).

So yes, we can indeed use Tauri to build Elm desktop apps with the hard disk used to preserve state — in this case a list of documents.

I would like to thank all of those who commented on an article I posted on Discourse on what turned out to be a poor initial strategy (using a localhost server). The comments on the post lead me to Tauri.

I would also like to thank the members of Tauri core team — @Denjell, @Laegel, and @lucasfernog — who generously gave of their time to help solve several problems and points of confusion on my part. Their help made it possible to make fast progress.

Here is the Github repo

6 Likes

PWA stands for Progressive Web Apps as mentioned already. In few words it allows one to install a web app as a native app, e.g. on desktop or mobile. Nowadays support for PWA is quite impressive. Big advantages are that no wrapper (like Electron or Tauri) required at all. What people do is they visit a website and click a link to install the app from there. Some platforms support direct installs, for other platforms is a link to add a web app to home screen, etc… It’s an easiest way to turn a web app into a native app. Disadvantages are that the app is basically limited to browser API’s.

For reference:

1 Like

PWAs are interesting iff you can stay within the bounds of web APIs which means, for example, no “easy” filesystem access

1 Like

No, deno creates a hash of that dependency on build, for each import and locks the dependency that way. It should alert you if a dependency changes below.
And I think it will bundle that deps up when you package your app, so it shouldn’t really be requested when your app has been deployed.

Yes, that is why I am currently developing the app with Tauri. It is giving me all I need, including convenient file access. I am really impressed with Tauri. I’ve kept the Deno server as a remote web server to which users can publish their files if they wish.

1 Like

Good to know about the hash of the dependency. I’ve been using Deno and Velociraptor a lot since I learned about them. Love the leanness: the bloat of node_modules has always bothered me.

Thank @akoppela, this may come in handy for me for other apps, but for the one I am currently working on, I need more than the web APIs.

1 Like